Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Вопрос Как написать ESP для Internal чита для Unity

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
2 Окт 2025
Сообщения
7
Реакции
0
Здравствуйте, кто может помочь буду благодарен какой день не мого написать ESP для INternal чита для игры на Unity (StandKnife) последний раз после не удачно попытки обратился к ИИ тоде не помогло нижи прикреплю код:

esp.cpp
#include "pch.h"
#include "esp.h"
#include "gui_framework.h"
#include <iostream>
#include <string>

namespace ESP {
bool enabled = false;

bool WorldToScreen(Vector3 world_pos, Vector2& screen_pos, Matrix4x4 view_matrix, int screen_width, int screen_height) {
float x = world_pos.x * view_matrix.m[0][0] + world_pos.y * view_matrix.m[0][1] + world_pos.z * view_matrix.m[0][2] + view_matrix.m[0][3];
float y = world_pos.x * view_matrix.m[1][0] + world_pos.y * view_matrix.m[1][1] + world_pos.z * view_matrix.m[1][2] + view_matrix.m[1][3];
float w = world_pos.x * view_matrix.m[3][0] + world_pos.y * view_matrix.m[3][1] + world_pos.z * view_matrix.m[3][2] + view_matrix.m[3][3];

if (w < 0.1f) return false;

screen_pos.x = (screen_width / 2.0f) * (1.0f + x / w);
screen_pos.y = (screen_height / 2.0f) * (1.0f - y / w);
return true;
}

namespace Signatures {
const char* GOM = "48 8B 15 ? ? ? ? 48 8B 1D ? ? ? ? 48 85 D2";
const char* CameraMain = "48 8B 05 ? ? ? ? 48 85 C0 74 ? 48 8B 40 ? 48 85 C0 74 ? 48 8B 80";
}

void InternalRender() {
ImDrawList* draw = ImGui::GetBackgroundDrawList();
ImGuiIO& io = ImGui::GetIO();
float screen_w = io.DisplaySize.x;
float screen_h = io.DisplaySize.y;

uintptr_t unity_player = (uintptr_t)GetModuleHandleA("UnityPlayer.dll");
uintptr_t game_assembly = (uintptr_t)GetModuleHandleA("GameAssembly.dll");
if (!unity_player || !game_assembly) return;

auto PatternScan = [](uintptr_t module_base, const char* signature) -> uintptr_t {
auto pattern_to_byte = [](const char* pattern) {
auto bytes = std::vector<int>{};
auto start = const_cast<char*>(pattern);
auto end = const_cast<char*>(pattern) + strlen(pattern);
for (auto curr = start; curr < end; ++curr) {
if (*curr == '?') {
++curr;
if (*curr == '?') ++curr;
bytes.push_back(-1);
} else {
bytes.push_back(strtoul(curr, &curr, 16));
}
}
return bytes;
};

auto dosHeader = (PIMAGE_DOS_HEADER)module_base;
auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)module_base + dosHeader->e_lfanew);
auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage;
auto patternBytes = pattern_to_byte(signature);
auto scanBytes = reinterpret_cast<std::uint8_t*>(module_base);

auto s = patternBytes.size();
auto d = patternBytes.data();

for (auto i = 0ul; i < sizeOfImage - s; ++i) {
bool found = true;
for (auto j = 0ul; j < s; ++j) {
if (scanBytes[i + j] != d[j] && d[j] != -1) {
found = false;
break;
}
}
if (found) return reinterpret_cast<uintptr_t>(&scanBytes);
}
return 0;
};

static uintptr_t gom_ptr = 0;
static float last_gom_search = 0;
float current_time = (float)GetTickCount64() / 1000.0f;

if (!gom_ptr && (current_time - last_gom_search > 2.0f)) {
last_gom_search = current_time;

// Пробуем несколько паттернов GOM
const char* patterns[] = {
"48 8B 15 ? ? ? ? 48 8B 1D ? ? ? ? 48 85 D2",
"48 8B 05 ? ? ? ? 48 8B 58 08 48 85 DB 74 33",
"48 8B 05 ? ? ? ? 48 8D 0D ? ? ? ? 48 89 05"
};

for (const char* pat : patterns) {
uintptr_t address = PatternScan(unity_player, pat);
if (address) {
int32_t relative_offset = *(int32_t*)(address + 3);
uintptr_t gom_ptr_addr = address + 7 + relative_offset;
if (!IsBadReadPtr((void*)gom_ptr_addr, sizeof(uintptr_t))) {
uintptr_t potential_gom = *(uintptr_t*)gom_ptr_addr;
if (potential_gom && !IsBadReadPtr((void*)potential_gom, 0x40)) {
gom_ptr = potential_gom;
break;
}
}
}
}

// Брутфорс сканирование секции данных (самый надежный способ)
if (!gom_ptr) {
auto dosHeader = (PIMAGE_DOS_HEADER)unity_player;
auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)unity_player + dosHeader->e_lfanew);
uintptr_t start = unity_player;
uintptr_t end = unity_player + ntHeaders->OptionalHeader.SizeOfImage;

for (uintptr_t i = start; i < end - 8; i += 8) {
if (IsBadReadPtr((void*)i, sizeof(uintptr_t))) continue;
uintptr_t potential_gom = *(uintptr_t*)i;
if (!potential_gom || (potential_gom % 8 != 0) || IsBadReadPtr((void*)potential_gom, 0x40)) continue;

uintptr_t tagged_list = *(uintptr_t*)(potential_gom + 0x08);
uintptr_t active_list = *(uintptr_t*)(potential_gom + 0x18);

if (tagged_list && !IsBadReadPtr((void*)tagged_list, 0x20) &&
active_list && !IsBadReadPtr((void*)active_list, 0x20)) {
uintptr_t first_obj = *(uintptr_t*)(active_list + 0x10);
if (first_obj && !IsBadReadPtr((void*)first_obj, 0x30)) {
gom_ptr = potential_gom;
break;
}
}
}
}
}

if (!gom_ptr || IsBadReadPtr((void*)gom_ptr, 0x40)) {
draw->AddText(ImVec2(10, 120), IM_COL32(255, 0, 0, 255), "ESP Error: GOM Not Found");
return;
}

Matrix4x4 view_matrix;
bool matrix_found = false;
char camera_name[64] = "None";
static float last_matrix_search = 0;
static uintptr_t cached_matrix_ptr = 0;

// Если есть кэшированный адрес матрицы, проверяем его
if (cached_matrix_ptr && !IsBadReadPtr((void*)cached_matrix_ptr, sizeof(Matrix4x4))) {
Matrix4x4 temp;
memcpy(&temp, (void*)cached_matrix_ptr, sizeof(Matrix4x4));
if (abs(temp.m[3][2]) > 0.1f) {
view_matrix = temp;
matrix_found = true;
strncpy_s(camera_name, "Cached_Matrix", 63);
} else {
cached_matrix_ptr = 0;
}
}

// Прямой поиск Main Camera через GOM (MainCameraTaggedNode - 0x10)
uintptr_t main_camera_node = *(uintptr_t*)(gom_ptr + 0x10);
if (main_camera_node && !IsBadReadPtr((void*)main_camera_node, 0x20)) {
uintptr_t camera_game_object = *(uintptr_t*)(main_camera_node + 0x10);
if (camera_game_object && !IsBadReadPtr((void*)camera_game_object, 0x100)) {
uintptr_t components = *(uintptr_t*)(camera_game_object + 0x30);
if (components && !IsBadReadPtr((void*)components, 0x100)) {
for (int i = 0; i < 40; i++) {
uintptr_t component_ptr = *(uintptr_t*)(components + (i * 0x10) + 0x8);
if (!component_ptr || IsBadReadPtr((void*)component_ptr, 0x100)) continue;

uintptr_t native_camera = *(uintptr_t*)(component_ptr + 0x28);
if (native_camera && !IsBadReadPtr((void*)native_camera, 0x700)) {
// Широкий поиск матрицы внутри объекта Camera
for (uintptr_t m_off = 0x0; m_off <= 0x600; m_off += 0x4) {
if (IsBadReadPtr((void*)(native_camera + m_off), sizeof(Matrix4x4))) continue;

Matrix4x4 temp;
memcpy(&temp, (void*)(native_camera + m_off), sizeof(Matrix4x4));

// Ультра-гибкая валидация: ViewProjection матрица
// В Unity x64 m[3][2] обычно 1.0 или -1.0, m[3][3] может быть 0.0 (для перспективы)
float m32 = abs(temp.m[3][2]);
float m33 = temp.m[3][3];

if ((m33 == 0.0f && m32 > 0.0001f && m32 < 10.0f) ||
(m33 == 1.0f && abs(temp.m[0][3]) < 0.0001f && m32 > 0.0001f)) {
view_matrix = temp;
matrix_found = true;
cached_matrix_ptr = native_camera + m_off;
strncpy_s(camera_name, "Unity_GOM_Camera_Deep", 63);
break;
}
}
}
if (matrix_found) break;
}
}
}
}

// Ультра-агрессивный поиск матрицы: сканирование всей памяти UnityPlayer.dll (Internal)
if (!matrix_found && (current_time - last_matrix_search > 2.0f)) {
last_matrix_search = current_time;

auto dosHeader = (PIMAGE_DOS_HEADER)unity_player;
auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)unity_player + dosHeader->e_lfanew);
uintptr_t start = unity_player;
uintptr_t end = unity_player + ntHeaders->OptionalHeader.SizeOfImage;

for (uintptr_t i = start; i < end - sizeof(Matrix4x4); i += 4) {
if (IsBadReadPtr((void*)i, sizeof(Matrix4x4))) continue;

Matrix4x4* temp = (Matrix4x4*)i;

// Проверка характерных признаков ViewProjection матрицы Unity
// m[3][0], m[3][1] обычно близки к 0 в экранных координатах
// m[3][2] (Z) обычно 1.0 или -1.0 для клип-спейса
// m[3][3] (W) обычно 0.0 или 1.0
if (abs(temp->m[3][0]) < 0.0001f && abs(temp->m[3][1]) < 0.0001f) {
float m32 = abs(temp->m[3][2]);
if ((m32 > 0.99f && m32 < 1.01f) && (temp->m[3][3] == 0.0f || temp->m[3][3] == 1.0f)) {
view_matrix = *temp;
matrix_found = true;
cached_matrix_ptr = i;
strncpy_s(camera_name, "Unity_Global_Matrix", 63);
break;
}
}
}
}

if (matrix_found) {
char debug_buf[128];
sprintf_s(debug_buf, "Camera: %s | Matrix: OK", camera_name);
draw->AddText(ImVec2(10, 140), IM_COL32(0, 255, 0, 255), debug_buf);

// Используем списки GOM для поиска игроков
uintptr_t player_lists[] = { 0x18, 0x08, 0x10 }; // Active, Tagged, MainCamera
int players_count = 0;

for (uintptr_t p_list_off : player_lists) {
uintptr_t p_list = *(uintptr_t*)(gom_ptr + p_list_off);
if (!p_list || IsBadReadPtr((void*)p_list, 0x20)) continue;

for (uintptr_t node = p_list; node != 0; node = *(uintptr_t*)(node + 0x08)) {
if (IsBadReadPtr((void*)node, 0x20)) break;

uintptr_t p_game_object = *(uintptr_t*)(node + 0x10);
if (!p_game_object || IsBadReadPtr((void*)p_game_object, 0x100)) continue;

uintptr_t p_name_ptr = *(uintptr_t*)(p_game_object + 0x60);
if (!p_name_ptr || IsBadReadPtr((void*)p_name_ptr, 64)) continue;

char p_name[64];
strncpy_s(p_name, (char*)p_name_ptr, 63);

// Проверка на игрока (расширенный список для StendKnife)
bool is_player = strstr(p_name, "Player") || strstr(p_name, "player") ||
strstr(p_name, "Soldier") || strstr(p_name, "Character") ||
strstr(p_name, "NetPlayer") || strstr(p_name, "Bot") ||
strstr(p_name, "Human") || strstr(p_name, "Enemy") ||
strstr(p_name, "BasePlayer") || strstr(p_name, "T_") || strstr(p_name, "CT_") ||
strstr(p_name, "Model") || strstr(p_name, "Ragdoll"); // Дополнительные имена

if (is_player) {
uintptr_t p_components = *(uintptr_t*)(p_game_object + 0x30);
if (IsBadReadPtr((void*)p_components, 0x100)) continue;

uintptr_t p_transform = 0;
// Transform в Unity x64 почти всегда первый компонент по оффсету 0x8 или 0x10
// Но в StendKnife мы ищем его во всем списке
for (int i = 0; i < 20; i++) {
uintptr_t comp_node = *(uintptr_t*)(p_components + (i * 0x10) + 0x08);
if (!comp_node || IsBadReadPtr((void*)comp_node, 0x30)) continue;

uintptr_t potential_transform = *(uintptr_t*)(comp_node + 0x28);
if (potential_transform && !IsBadReadPtr((void*)(potential_transform + 0x38), 0x100)) {
// Проверка иерархии Transform (у корня m_Parent == 0 или валидный указатель)
uintptr_t parent = *(uintptr_t*)(potential_transform + 0x38);
if (parent == 0 || !IsBadReadPtr((void*)parent, 0x30)) {
p_transform = potential_transform;
break;
}
}
}

if (p_transform) {
// В Unity x64 m_LocalPosition лежит по 0x90, но мировые координаты
// в StendKnife могут быть в другом месте или требовать Update
// Попробуем прочитать 0x90 как позицию
Vector3 pos;
if (!IsBadReadPtr((void*)(p_transform + 0x90), sizeof(Vector3))) {
pos = *(Vector3*)(p_transform + 0x90);
} else {
continue;
}

Vector2 screen;
if (WorldToScreen(pos, screen, view_matrix, (int)screen_w, (int)screen_h)) {
// Дистанция через m[3] (W)
float w_dist = pos.x * view_matrix.m[0][3] + pos.y * view_matrix.m[1][3] + pos.z * view_matrix.m[2][3] + view_matrix.m[3][3];
if (w_dist < 0.1f) {
w_dist = pos.x * view_matrix.m[3][0] + pos.y * view_matrix.m[3][1] + pos.z * view_matrix.m[3][2] + view_matrix.m[3][3];
}

if (w_dist > 0.1f) {
players_count++;
float h = 1000.0f / w_dist;
if (h < 2.0f || h > 2000.0f) h = 100.0f;
float w = h * 0.5f;

draw->AddRect(ImVec2(screen.x - w / 2, screen.y - h), ImVec2(screen.x + w / 2, screen.y), GUI::Colors::Accent, 0, 0, 1.5f);
draw->AddText(ImVec2(screen.x - w / 2, screen.y - h - 15), GUI::Colors::text_main, p_name);
}
}
}
}
}
}

char count_buf[64];
sprintf_s(count_buf, "Players found: %d", players_count);
draw->AddText(ImVec2(10, 160), IM_COL32(255, 255, 255, 255), count_buf);
}
else {
draw->AddText(ImVec2(10, 140), IM_COL32(255, 255, 0, 255), "ESP: Searching Matrix...");
}
}

void Render() {
if (!enabled) return;

__try {
InternalRender();
}
__except (EXCEPTION_EXECUTE_HANDLER) {}
}
}
 
Назад
Сверху Снизу