UseRay.exe

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <raylib.h>
#include <raymath.h>
#include <iostream>

int main() {
SetConfigFlags(FLAG_WINDOW_UNDECORATED);
InitWindow(1280, 720, "FPS: Realistic Scale Demo");

// 1. 玩家相机
Camera3D camera = { 0 };
camera.position = Vector3{ 10.0f, 1.75f, 10.0f };
camera.target = Vector3{ 0.0f, 1.75f, 0.0f };
camera.up = Vector3{ 0.0f, 1.0f, 0.0f };
camera.fovy = 70.0f;
camera.projection = CAMERA_PERSPECTIVE;

// 2. 敌人状态
Vector3 enemyPos = { 0.0f, 0.0f, 0.0f };
Vector3 enemyVel = { 0.12f, 0.0f, 0.08f };
#include <stddef.h> // 引入 offsetof
// --- 关键:打印地址 ---
// 使用 std::hex 以十六进制格式输出,方便在 Cheat Engine 或 Search.exe 中使用
std::cout << "========================================" << std::endl;
std::cout << "ENEMY POSITION ADDRESS: 0x" << std::hex << (uintptr_t)&enemyPos << std::endl;
// 打印偏移量,方便 Search.exe 使用
std::cout << "[OFFSET] enemyPos.x: +0x" << offsetof(enemyPos, x) << std::endl;
std::cout << "[OFFSET] enemyPos.y: +0x" << offsetof(enemyPos, y) << std::endl;
std::cout << "[OFFSET] enemyPos.z: +0x" << offsetof(enemyPos, z) << std::endl;
// 获取 Raylib 内部矩阵的方法 (rlgl)
// 注意:你需要包含 #include "rlgl.h" 才能调用这些
// 这里我们先打印 enemyPos,因为矩阵通常在 rlgl 内部比较深的地方
// 打印矩阵地址(这就是你要的 CAMERA_ADDR)
std::cout << "CAMERA_ADDR: 0x" << std::hex << (uintptr_t)&camera << std::endl;


// --- 新增:暂停开关 ---
bool isPaused = false;

SetTargetFPS(60);
DisableCursor();

while (!WindowShouldClose()) {
// --- 逻辑:按空格键切换暂停/继续 ---
if (IsKeyPressed(KEY_SPACE)) isPaused = !isPaused;

UpdateCamera(&camera, CAMERA_FIRST_PERSON);

// --- 逻辑:只有在非暂停状态下才更新位置 ---
if (!isPaused) {
enemyPos = Vector3Add(enemyPos, enemyVel);

if (enemyPos.x > 30.0f || enemyPos.x < -30.0f) enemyVel.x *= -1;
if (enemyPos.z > 30.0f || enemyPos.z < -30.0f) enemyVel.z *= -1;

if (GetRandomValue(0, 100) < 2) {
float angle = GetRandomValue(0, 360) * DEG2RAD;
enemyVel.x = cos(angle) * 0.15f;
enemyVel.z = sin(angle) * 0.15f;
}
}

// --- 渲染 ---
BeginDrawing();
ClearBackground(BLACK);
BeginMode3D(camera);
DrawPlane(Vector3 { 0, 0, 0 }, Vector2 { 100, 100 }, DARKGRAY);
// 绘制敌人
DrawCapsule(enemyPos, Vector3Add(enemyPos, Vector3 { 0, 1.8f, 0 }), 0.3f, 8, 4, RED);
EndMode3D();

// 状态提示
DrawText(isPaused ? "STATUS: PAUSED (SPACE to Resume)" : "STATUS: RUNNING (SPACE to Pause)", 20, 20, 20, isPaused ? YELLOW : GREEN);
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 2, SKYBLUE);
EndDrawing();
}
CloseWindow();
return 0;
}

Search.exe

通过反方的位置地址-0x50的偏移找到相机,反方的位置通过匹配特征码找到地址,在地址中读取rbp的值+0x58的偏移找到反方的x坐标地址。

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <raylib.h>
#include "ESPContext.h"
#include "ESPLogic.h"
#include "ESPView.h"

#ifndef _DEBUG
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址
#endif

int main() {

// 1. 初始化 Overlay 窗口特性
SetConfigFlags(FLAG_WINDOW_UNDECORATED | FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_TOPMOST | FLAG_WINDOW_MOUSE_PASSTHROUGH);
InitWindow(1280, 720, "Raylib_ESP_MVC");
SetTargetFPS(0);

ESPContext ctx;
ESPLogic logic;
ESPView view;

while (!WindowShouldClose()) {
// --- 逻辑:读内存、计算坐标 ---
logic.Update(ctx);

// --- 渲染:把结果画出来 ---
BeginDrawing();
ClearBackground(BLANK);

view.Draw(ctx);

EndDrawing();
}

CloseWindow();
return 0;
}

ESPContext.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma once
#include <raylib.h>
#include <vector>

struct ESPContext {
// 进程信息
unsigned int targetPid = 0;
bool isGameRunning = false;

// 渲染参数
float screenWidth = 1280.0f;
float screenHeight = 720.0f;

// 每一帧抓取的数据
struct Entity {
Vector3 pos;
Vector2 screenFoot;
Vector2 screenHead;
float distance;
bool onScreen;
};

std::vector<Entity> entities; // 支持以后扩展多个敌人
Matrix viewProjMatrix;
};

ESPView.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma once
#include "ESPContext.h"

class ESPView {
public:
void Draw(const ESPContext& ctx) {
if (!ctx.isGameRunning) {
DrawText("WAITING FOR GAME...", 10, 10, 20, GRAY);
return;
}

for (const auto& entity : ctx.entities) {
if (!entity.onScreen) continue;

float height = entity.screenFoot.y - entity.screenHead.y;
float width = height / 2.0f;

// 绘制骨架方框
DrawRectangleLinesEx(
{ entity.screenHead.x - width / 2, entity.screenHead.y, width, height },
2.0f, RED
);

// 绘制距离标签
DrawText(TextFormat("[%.1fm]", entity.distance),
(int)entity.screenFoot.x - 20, (int)entity.screenFoot.y + 5,
15, YELLOW);
}

// 辅助:画准星
DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, 2, GREEN);
}
};

ESPLogic.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once
#include "ESPContext.h"
#include "WindowUtils.h"
#include <raymath.h>
#include <iostream>


class ESPLogic {
public:
// 构造时绑定目标信息
ESPLogic() : _game("FPS: Realistic Scale Demo", "GLFW30") {}

void Update(ESPContext& ctx) {

// 1. 利用类成员进行进程有效性检查
if (!_game.IsTargetValid()) {
ctx.isGameRunning = false;
ctx.targetPid = 0;
return;
}

ctx.targetPid = _game.GetPid();

// 2. 获取最新的客户区信息(同步窗口大小与位置)
ClientAreaInfo info = _game.GetClientInfo();
ctx.isGameRunning = info.isVisible;
ctx.screenWidth = (float)info.width;
ctx.screenHeight = (float)info.height;

if (ctx.isGameRunning) {
// 同步 Overlay 窗口位置到游戏客户区
_game.SyncOverlayPosition(GetWindowHandle());

// 3. 执行核心数据刷新
RefreshGameData(ctx);
}
}

private:
ProcessManager _game; // 核心管理类作为成员
uint8_t savedOffset;
void Init() {
this->savedOffset = _game.ExtractStackOffset();
}

void RefreshGameData(ESPContext& ctx) {
if (!_game.IsTargetValid()) return;

RemoteCamera remoteCam;
Vector3 enemyPos;

// 1. 获取数据
if (!FetchRawData(remoteCam, enemyPos)) return;

// 2. 矩阵逻辑封装(这部分可以留在 Refresh 或单独分出)
Camera cam = {
{ remoteCam.position.x, remoteCam.position.y, remoteCam.position.z },
{ remoteCam.target.x, remoteCam.target.y, remoteCam.target.z },
{ remoteCam.up.x, remoteCam.up.y, remoteCam.up.z },
remoteCam.fovy, remoteCam.projection
};

Matrix view = GetCameraMatrix(cam);
float aspect = ctx.screenWidth / ctx.screenHeight;
Matrix proj = MatrixPerspective(cam.fovy * DEG2RAD, aspect, 0.01f, 1000.0f);
ctx.viewProjMatrix = MatrixMultiply(view, proj);

// 4. 坐标转换并存入 Context
ctx.entities.clear();
UpdateEntityESP(ctx, enemyPos);

}
// 内部数学工具函数
bool WorldToScreen(Vector3 pos, Matrix vp, float sw, float sh, Vector2& out, float& w_out) {
float x = pos.x * vp.m0 + pos.y * vp.m4 + pos.z * vp.m8 + vp.m12;
float y = pos.x * vp.m1 + pos.y * vp.m5 + pos.z * vp.m9 + vp.m13;
float w = pos.x * vp.m3 + pos.y * vp.m7 + pos.z * vp.m11 + vp.m15;

w_out = w;
if (w < 0.1f) return false;

float ndc_x = x / w;
float ndc_y = y / w;

out.x = (sw / 2.0f) * (1.0f + ndc_x);
out.y = (sh / 2.0f) * (1.0f - ndc_y);
return true;
}

bool FetchRawData(RemoteCamera& cam, Vector3& enemyPos) {

// 使用类成员代替 static
if (_game._cachedOffset == 0) {
_game._cachedOffset = _game.ExtractStackOffset();
if (_game._cachedOffset == 0) return false;
}

uintptr_t rbp = _game.GetThreadStackBase();

if (rbp == 0) return false;

uintptr_t enemyXAddr = rbp + _game._cachedOffset;

enemyPos = _game.Read<Vector3>(enemyXAddr);
cam = _game.Read<RemoteCamera>(enemyXAddr - 0x50);
return true;
}
void UpdateEntityESP(ESPContext& ctx, Vector3& enemyPos)
{
ESPContext::Entity e;
e.pos = enemyPos;

float w_foot, w_head;
// 使用你调试成功的 2.1f 高度
e.onScreen = WorldToScreen(e.pos, ctx.viewProjMatrix, ctx.screenWidth, ctx.screenHeight, e.screenFoot, w_foot);
bool headOnScreen = WorldToScreen(Vector3Add(e.pos, { 0, 2.1f, 0 }), ctx.viewProjMatrix, ctx.screenWidth, ctx.screenHeight, e.screenHead, w_head);

// 只有脚在屏幕内才添加(或者你可以根据需求调整逻辑)
if (e.onScreen) {
e.distance = w_foot;
ctx.entities.push_back(e);
}
}


};

WindowUtils.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#pragma once
#include <stdint.h>
#include <string>
#include <vector>

// 客户区信息包
struct ClientAreaInfo {
int x, y;
int width, height;
bool isVisible;
};

// 内存数据结构
struct MyVector3 { float x, y, z; };
struct RemoteCamera {
MyVector3 position;
MyVector3 target;
MyVector3 up;
float fovy;
int projection;
};

class ProcessManager {
public:
ProcessManager(const std::string& title, const std::string& className);
~ProcessManager();

// 进程与窗口状态
bool IsTargetValid();
uint32_t GetPid() const { return _pid; }
ClientAreaInfo GetClientInfo();

// 窗口同步逻辑
void SyncOverlayPosition(void* overlayHandle);

// 内存读取模板
template <typename T>
T Read(uintptr_t address) {
T buffer = {};
ReadMemoryInternal(address, &buffer, sizeof(T));
return buffer;
}
uintptr_t GetModuleBase(const std::string& moduleName);
uintptr_t GetModuleBase(const std::wstring& moduleName);
uintptr_t GetThreadStackBase();
uintptr_t FindPattern(const char* pattern, const std::string& moduleName);
uint8_t ExtractStackOffset();
uintptr_t GetThreadStackBaseWithCache(int intervalMs);
bool SetThreadRbp(uintptr_t newValue);
void UpdateThreadHandle(unsigned long tid);


private:
bool ReadMemoryInternal(uintptr_t address, void* buffer, size_t size);

std::string _windowTitle;
std::string _className;
uint32_t _pid = 0;
void* _processHandle = nullptr; // 内部存 HANDLE
void* _mainThreadHandle = nullptr;
uintptr_t _cachedRbp;
unsigned long _lastRbpTick;
public:
uint8_t _cachedOffset = 0; // 改为成员变量
};

WindowUtils.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#include "WindowUtils.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>

ProcessManager::ProcessManager(const std::string& title, const std::string& className)
: _windowTitle(title), _className(className) {
}

ProcessManager::~ProcessManager() {
if (_mainThreadHandle) CloseHandle(_mainThreadHandle);
if (_processHandle) CloseHandle(_processHandle);
}
bool ProcessManager::IsTargetValid() {

// 1. 如果已经持有句柄,检查进程是否依然存活
if (_processHandle) {
DWORD exitCode = 0;
GetExitCodeProcess((HANDLE)_processHandle, &exitCode);
if (exitCode == STILL_ACTIVE) return true;

_cachedOffset = 0; // 关键:当游戏关了,把偏移也清空
// 进程已退出,清理所有旧句柄
CloseHandle((HANDLE)_processHandle);
if (_mainThreadHandle) CloseHandle((HANDLE)_mainThreadHandle);
_processHandle = nullptr;
_mainThreadHandle = nullptr;
_pid = 0;
}

// 2. 尝试寻找游戏窗口
HWND hwnd = FindWindowA(_className.empty() ? NULL : _className.c_str(), _windowTitle.c_str());
if (!hwnd) return false;

// 3. 找到窗口后,初始化 PID 和双重句柄 (Process + Thread)
DWORD tid = GetWindowThreadProcessId(hwnd, (LPDWORD)&_pid);

// 获取进程句柄:用于 ReadProcessMemory
_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _pid);

// 获取主线程句柄:用于 GetThreadContext (RBP)
// 权限包含:GET(读), SET(写), SUSPEND(挂起)
if (tid != 0) {
_mainThreadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE, tid);
}

// 只有两个句柄都拿到了,才算真正的“有效”
return (_processHandle != nullptr && _mainThreadHandle != nullptr);
}

// 在 ProcessManager 类里加一个成员
HANDLE _mainThreadHandle = nullptr;

// 获取主线程句柄的函数(只在初始化或失效时调用)
void ProcessManager::UpdateThreadHandle(DWORD tid) {
if (_mainThreadHandle) CloseHandle(_mainThreadHandle);

// 权限要给够,不然读不了寄存器
_mainThreadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE, tid);
}

ClientAreaInfo ProcessManager::GetClientInfo() {
ClientAreaInfo info = { 0, 0, 0, 0, false };
HWND hwnd = FindWindowA(_className.empty() ? NULL : _className.c_str(), _windowTitle.c_str());

if (hwnd && IsWindow(hwnd)) {
info.isVisible = (GetForegroundWindow() == hwnd);

RECT cRect;
GetClientRect(hwnd, &cRect);
info.width = cRect.right - cRect.left;
info.height = cRect.bottom - cRect.top;

POINT pt = { 0, 0 };
ClientToScreen(hwnd, &pt);
info.x = pt.x;
info.y = pt.y;
}
return info;
}

void ProcessManager::SyncOverlayPosition(void* overlayHandle) {
HWND myHwnd = (HWND)overlayHandle;
ClientAreaInfo info = GetClientInfo();

if (info.width > 0 && info.isVisible) {
if (!IsWindowVisible(myHwnd)) ShowWindow(myHwnd, SW_SHOWNOACTIVATE);

// 只有位置变化时才移动,减少抖动
static int lastX = 0, lastY = 0;
if (info.x != lastX || info.y != lastY) {
SetWindowPos(myHwnd, HWND_TOPMOST, info.x, info.y, info.width, info.height, SWP_NOACTIVATE);
lastX = info.x; lastY = info.y;
}
}
else {
if (IsWindowVisible(myHwnd)) ShowWindow(myHwnd, SW_HIDE);
}
}

bool ProcessManager::ReadMemoryInternal(uintptr_t address, void* buffer, size_t size) {
if (!_processHandle) return false;
SIZE_T read;
return ReadProcessMemory((HANDLE)_processHandle, (LPCVOID)address, buffer, size, &read) && (read == size);
}


uintptr_t ProcessManager::GetModuleBase(const std::wstring& moduleName) {
uintptr_t dwModuleBaseAddress = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, _pid);
if (hSnapshot != INVALID_HANDLE_VALUE) {
MODULEENTRY32 ModuleEntry32;
ModuleEntry32.dwSize = sizeof(MODULEENTRY32W);
if (Module32FirstW(hSnapshot, &ModuleEntry32)) {
do {
if (moduleName == ModuleEntry32.szModule) {
dwModuleBaseAddress = (uintptr_t)ModuleEntry32.modBaseAddr;
break;
}
} while (Module32NextW(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}

uintptr_t ProcessManager::GetModuleBase(const std::string& moduleName) {
uintptr_t dwModuleBaseAddress = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, _pid);
if (hSnapshot != INVALID_HANDLE_VALUE) {
MODULEENTRY32W ModuleEntry32; // 显式使用 W 版本 (Unicode)
ModuleEntry32.dwSize = sizeof(MODULEENTRY32W);

// 将 std::string 转为 std::wstring
std::wstring wModuleName(moduleName.begin(), moduleName.end());

if (Module32FirstW(hSnapshot, &ModuleEntry32)) {
do {
if (wModuleName == ModuleEntry32.szModule) {
dwModuleBaseAddress = (uintptr_t)ModuleEntry32.modBaseAddr;
break;
}
} while (Module32NextW(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}

uintptr_t ProcessManager::GetThreadStackBase() {
if (!_mainThreadHandle) return 0; // 直接使用 IsTargetValid 准备好的钥匙

alignas(16) CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

if (SuspendThread((HANDLE)_mainThreadHandle) != (DWORD)-1) {
if (GetThreadContext((HANDLE)_mainThreadHandle, &ctx)) {
ResumeThread((HANDLE)_mainThreadHandle);
return ctx.Rbp; // 现在的耗时应该低于 1000us
}
ResumeThread((HANDLE)_mainThreadHandle);
}
return 0;
}

// 辅助函数:将十六进制字符串转为字节数组(支持 ?? 通配符)
// 例如 "F3 0F 10 45 ??"
uintptr_t ProcessManager::FindPattern(const char* pattern, const std::string& moduleName) {
uintptr_t base = GetModuleBase(moduleName);// 获取 UseRay.exe 基址
std::cout << "[Debug] Searching " << moduleName << " at Base: " << std::hex << base << std::endl;
if (!base) {
std::cout << "[Error] Cannot find Base for: " << moduleName << std::endl;
return 0;
}

size_t searchRange = 0x6400000; // 通常代码段 2MB 足够,或者动态获取大小
std::vector<uint8_t> moduleMemory(searchRange);
SIZE_T bytesRead = 0;

// 检查读取是否成功
if (!ReadProcessMemory((HANDLE)_processHandle, (LPCVOID)base, moduleMemory.data(), searchRange, &bytesRead)) {
// 打印错误代码,如果是 299 (ERROR_PARTIAL_COPY),说明 searchRange 设太大了,读到了无效地址
std::cout << "[Debug] RPM Failed, Error: " << GetLastError() << " BytesRead: " << bytesRead << std::endl;
}


// 解析 Pattern 字符串
std::vector<int> patternBytes;
std::string p = pattern;
for (size_t i = 0; i < p.length(); i++) {
if (p[i] == ' ') continue;
if (p[i] == '?') {
patternBytes.push_back(-1); // -1 代表通配符
if (p[i + 1] == '?') i++;
}
else {
patternBytes.push_back(std::stoi(p.substr(i, 2), nullptr, 16));
i++;
}
}

// 暴力匹配 (也可以换成更快的 Boyer-Moore 算法)
for (size_t i = 0; i < bytesRead - patternBytes.size(); i++) {
bool found = true;
for (size_t j = 0; j < patternBytes.size(); j++) {
if (patternBytes[j] != -1 && moduleMemory[i + j] != patternBytes[j]) {
found = false;
break;
}
}
if (found) return base + i;
}
return 0;
}

uint8_t ProcessManager::ExtractStackOffset() {
// 传入正确的进程模块名
uintptr_t instructionAddr = FindPattern("F3 0F 10 45 ??", "UseRay.exe");

if (instructionAddr != 0) {
uint8_t offset = 0;
ReadProcessMemory((HANDLE)_processHandle, (LPCVOID)(instructionAddr + 4), &offset, 1, NULL);
std::cout << "[Success] Found Pattern at: " << std::hex << instructionAddr << " Offset: " << (int)offset << std::endl;
return offset;
}
std::cout << "[Error] Pattern not found!" << std::endl;
return 0;
}

uintptr_t ProcessManager::GetThreadStackBaseWithCache(int intervalMs) {
DWORD currentTick = GetTickCount(); // 这里可以用 DWORD,因为在 WindowUtils.cpp 里

if (_cachedRbp == 0 || (currentTick - _lastRbpTick) > (DWORD)intervalMs) {
// 执行原本那个复杂的 Snapshot 和 GetThreadContext 逻辑
_cachedRbp = this->GetThreadStackBase();
_lastRbpTick = currentTick;
}

return _cachedRbp;
}
//写入寄存器功能
bool ProcessManager::SetThreadRbp(uintptr_t newValue) {
// 确保句柄有效且拥有 THREAD_SET_CONTEXT 权限
if (!_mainThreadHandle || _mainThreadHandle == INVALID_HANDLE_VALUE) return false;

// 挂起线程。注意:SuspendThread 返回的是挂起前的计数
if (SuspendThread(_mainThreadHandle) == (DWORD)-1) return false;

// 必须 16 字节对齐,这是 x64 CONTEXT 结构体的硬性要求
alignas(16) CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_FULL;

bool success = false;
// 先读再写,确保不破坏 RIP 等其他关键寄存器
if (GetThreadContext(_mainThreadHandle, &ctx)) {
ctx.Rbp = (DWORD64)newValue;

if (SetThreadContext(_mainThreadHandle, &ctx)) {
success = true;
}
}

// 无论如何都要恢复线程
ResumeThread(_mainThreadHandle);
return success;
}