Silent Aim & EntityList
i got a lot of requests from people asking about silent aim or EntityList
because there are so many i can’t reply to everyone
so i made this post for everyone to benefit from
first before the explanation starts there are some points to mention
first the explanation will be in c++ cuz most people here know and use it
second using this source is your own responsibility it’s just for explanation only if it causes u a ban that’s not on me
let’s start the explanation now
Explanation of Entity Extraction (GetAllEntities) and Silent Aim System in Trove:
Part 1: ------------Extracting Entities (GetAllEntities)
1- Understanding the Data Structure: Linked List in Game Memory
The game doesn’t store all entities in a single fixed location
Instead, it uses a linked list
Each entity contains a pointer to the next entity
This approach is flexible and allows adding or removing entities without rearranging all memory
2- Finding the Starting Point (Base Address)
Everything starts from the World address in memory
We use a GetAddress function with specific offsets to reach it:
This address acts like the main key to the game world in memory
3- Accessing the List Info (Node Info)
From world, we go to offset 0x7C to get the linked list info address:
4- Reading the List Data (Base Address, Size, Step)
Inside nodeInfo we read:
baseAddr: start of the memory region containing entities
size: number of entities
step: byte distance between consecutive entities
Code example:
5- Iterating Through the List to Collect Entity Addresses
Start at baseAddr
Move in increments of step bytes
At each step, read the next pointer to the next element
Continue until you hit a null or invalid pointer
6- Extracting Each Entity’s Data
For each address in nodes, follow specific offsets to get the actual entity address:
Then read entity data like position, health, level, etc., similarly
7- Result
The function returns a ready-to-use vector/list of entities for any system you want (tracking, targeting, analysis)
Part 2: ------------Silent Aim System
1- Silent Aim Concept
Instead of moving the camera or mouse to aim, you modify the forward vector used by the game for aiming
This way you hit targets without visible camera movement, making it look legit
2- Allocating Memory in the Game for the Forward Vector
Reserve 3 float slots for X, Y, Z coordinates in the game’s memory using VirtualAllocEx:
3- Finding the Closest Entity and Targeting
Read player and camera positions
Loop through entities calculating distance
Pick the closest entity within a max range (e.g., 40 units):
4- Calculating the Forward Vector
Compute the vector from camera to target:
5- Writing the Vector to Game Memory
Write the negated values (game expects inverted vector):
6- Patching Game Instructions Using silentAimOffsets With Instruction Signatures
Fixed offsets for movss instructions that read the vector values:
We patch instructions to point to our new memory addresses:
7- Why Use This Patching Method?
Cleaner and simpler than manually editing each instruction and calculating relative addresses
Centralizes changes to a fixed memory area
Easy to revert by restoring original instruction bytes stored earlier
8- Cleaning Up Allocated Memory
After done, free allocated memory:
Summary:
* Entities extracted by traversing a linked list in game memory step by step
* Silent Aim works by modifying aiming vector, no visible camera movement
* Using fixed offsets and absolute addressing for patching is safe, clean, and reversible
* Proper allocation and freeing of memory ensures stability
finally i wanna say of course i won’t leave u hanging
i made a simple source code and a tool u can use right away or check anything in it
good luck to everyone
because there are so many i can’t reply to everyone
so i made this post for everyone to benefit from
first before the explanation starts there are some points to mention
first the explanation will be in c++ cuz most people here know and use it
second using this source is your own responsibility it’s just for explanation only if it causes u a ban that’s not on me
let’s start the explanation now
Explanation of Entity Extraction (GetAllEntities) and Silent Aim System in Trove:
Part 1: ------------Extracting Entities (GetAllEntities)
1- Understanding the Data Structure: Linked List in Game Memory
The game doesn’t store all entities in a single fixed location
Instead, it uses a linked list
Each entity contains a pointer to the next entity
This approach is flexible and allows adding or removing entities without rearranging all memory
2- Finding the Starting Point (Base Address)
Everything starts from the World address in memory
We use a GetAddress function with specific offsets to reach it:
Code:
uintptr_t world = GetAddress(proc, base, {0x11F8514, 0x0});
3- Accessing the List Info (Node Info)
From world, we go to offset 0x7C to get the linked list info address:
Code:
uintptr_t nodeInfo = GetAddress(hProcess, world, {0x7C});
Inside nodeInfo we read:
baseAddr: start of the memory region containing entities
size: number of entities
step: byte distance between consecutive entities
Code example:
Code:
ReadValue(hProcess, nodeInfo, "uint", &baseAddr);
ReadValue(hProcess, GetAddress(hProcess, nodeInfo, {0x8}), "uint", &size);
ReadValue(hProcess, GetAddress(hProcess, nodeInfo, {0x4}), "uint", &step);
Start at baseAddr
Move in increments of step bytes
At each step, read the next pointer to the next element
Continue until you hit a null or invalid pointer
Code:
for (uint32_t i = 0; i < size; ++i) {
uintptr_t addr = baseAddr + i * step;
while (addr) {
uint32_t next = 0;
if (!ReadValue(hProcess, addr, "uint", &next)) break;
if (next != 1) nodes.push_back(addr);
addr = next & ~1u; // Clear lowest bit as flag
}
}
For each address in nodes, follow specific offsets to get the actual entity address:
Code:
uintptr_t ent = GetAddress(hProcess, node, {0x10, 0xC4, 0x4, 0x0});
if (!ent) continue;
7- Result
The function returns a ready-to-use vector/list of entities for any system you want (tracking, targeting, analysis)
Part 2: ------------Silent Aim System
1- Silent Aim Concept
Instead of moving the camera or mouse to aim, you modify the forward vector used by the game for aiming
This way you hit targets without visible camera movement, making it look legit
2- Allocating Memory in the Game for the Forward Vector
Reserve 3 float slots for X, Y, Z coordinates in the game’s memory using VirtualAllocEx:
Code:
void* addr = VirtualAllocEx(hProcess, nullptr, sizeof(float), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); allocatedSilentAimAddresses[i] = reinterpret_cast<uintptr_t>(addr);
Read player and camera positions
Loop through entities calculating distance
Pick the closest entity within a max range (e.g., 40 units):
Code:
if (dist < closestDist && dist <= MAX_RANGE) {
closestDist = dist;
closestEntity = e;
}
Compute the vector from camera to target:
Code:
auto [fx, fy, fz] = GetForwardVector(cx, cy, cz, closestEntity.x, closestEntity.y, closestEntity.z);
5- Writing the Vector to Game Memory
Write the negated values (game expects inverted vector):
Code:
WriteFloat(hProcess, allocatedSilentAimAddresses[0], -fx); WriteFloat(hProcess, allocatedSilentAimAddresses[1], -fy); WriteFloat(hProcess, allocatedSilentAimAddresses[2], -fz);
Fixed offsets for movss instructions that read the vector values:
Code:
const std::array<uintptr_t, 3> silentAimOffsets = {
0x2FDCA3, // F3 0F 10 82 DC 00 00 00 (X component)
0x2FDCD9, // F3 0F 10 82 E0 00 00 00 (Y component)
0x2FDD0F // F3 0F 10 82 E4 00 00 00 (Z component)
};
Code:
BYTE patch[8] = { 0xF3, 0x0F, 0x10, 0x05 }; // movss with absolute address
memcpy(patch + 4, &allocatedSilentAimAddresses[index], 4);
WriteBytes(hProcess, base + silentAimOffsets[index], patch, 8);
Cleaner and simpler than manually editing each instruction and calculating relative addresses
Centralizes changes to a fixed memory area
Easy to revert by restoring original instruction bytes stored earlier
8- Cleaning Up Allocated Memory
After done, free allocated memory:
Code:
VirtualFreeEx(hProcess, (LPVOID)allocatedSilentAimAddresses[i], 0, MEM_RELEASE);
* Entities extracted by traversing a linked list in game memory step by step
* Silent Aim works by modifying aiming vector, no visible camera movement
* Using fixed offsets and absolute addressing for patching is safe, clean, and reversible
* Proper allocation and freeing of memory ensures stability
finally i wanna say of course i won’t leave u hanging
i made a simple source code and a tool u can use right away or check anything in it
good luck to everyone
source code
Code:
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
#include <cstdint>
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <cfloat>
#include <array>
#include <cstdint>
// Define localPlayer offset
const uintptr_t localPlayerOffset = 0x11FAD74;
// Blacklist keywords
const std::vector<std::string> blacklist_keywords = {
"pet", "portal", "abilities", "placeable", "cornerstone",
"services", "client", "karma", "outpost", "minion", "custom"
};
// Offsets for positions, camera, and silent aim
const std::vector<uintptr_t> positionOffsets = {localPlayerOffset, 0x8, 0x28, 0xC4, 0x4, 0x80};
const std::vector<uintptr_t> camOffsets = {localPlayerOffset, 0x20, 0x70};
const std::array<uintptr_t, 3> silentAimOffsets = {
0x2FDCA3, // F3 0F 10 82 DC 00 00 00
0x2FDCD9, // F3 0F 10 82 E0 00 00 00
0x2FDD0F // F3 0F 10 82 E4 00 00 00
};
// Max range for targeting entities
const float MAX_RANGE = 40.0f;
struct Entity {
std::string name;
float x, y, z;
float scale;
int level;
int death;
double health;
};
uintptr_t GetAddress(HANDLE hProcess, uintptr_t base, const std::vector<uintptr_t>& offsets) {
uintptr_t address = base;
for (size_t i = 0; i + 1 < offsets.size(); ++i) {
uint32_t tmp = 0;
if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address + offsets[i]), &tmp, sizeof(tmp), nullptr) || tmp == 0) {
return 0;
}
address = tmp;
}
return offsets.empty() ? address : (address + offsets.back());
}
float ReadFloat(HANDLE hProcess, uintptr_t address) {
float value = 0.0f;
ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address), &value, sizeof(value), nullptr);
return value;
}
bool WriteFloat(HANDLE hProcess, uintptr_t address, float value) {
SIZE_T bytesWritten;
bool result = WriteProcessMemory(hProcess, reinterpret_cast<LPVOID>(address), &value, sizeof(value), &bytesWritten);
return result && bytesWritten == sizeof(value);
}
std::string ReadString(HANDLE hProcess, uintptr_t address, size_t maxLen) {
std::vector<char> buffer(maxLen);
SIZE_T bytesRead;
if (!ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address), buffer.data(), maxLen, &bytesRead)) {
return {};
}
size_t len = 0;
while (len < bytesRead && buffer[len] != '\0') ++len;
return std::string(buffer.data(), len);
}
bool ReadValue(HANDLE hProcess, uintptr_t address, const std::string& type, void* out) {
SIZE_T bytesRead;
if (type == "float") {
return ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address), out, sizeof(float), &bytesRead) && bytesRead == sizeof(float);
} else if (type == "uint") {
return ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address), out, sizeof(uint32_t), &bytesRead) && bytesRead == sizeof(uint32_t);
} else if (type == "double") {
return ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address), out, sizeof(double), &bytesRead) && bytesRead == sizeof(double);
} else if (type == "int") {
return ReadProcessMemory(hProcess, reinterpret_cast<LPCVOID>(address), out, sizeof(int32_t), &bytesRead) && bytesRead == sizeof(int32_t);
}
return false;
}
std::vector<Entity> GetAllEntities(HANDLE hProcess, uintptr_t world) {
std::vector<Entity> entities;
if (!world) return entities;
uintptr_t nodeInfo = GetAddress(hProcess, world, {0x7C});
if (!nodeInfo) return entities;
uint32_t baseAddr = 0;
ReadValue(hProcess, nodeInfo, "uint", &baseAddr);
if (!baseAddr) return entities;
uint32_t size = 0, step = 0;
uintptr_t sizeAddr = GetAddress(hProcess, nodeInfo, {0x8});
ReadValue(hProcess, sizeAddr, "uint", &size);
uintptr_t stepAddr = GetAddress(hProcess, nodeInfo, {0x4});
ReadValue(hProcess, stepAddr, "uint", &step);
std::vector<uintptr_t> nodes;
for (uint32_t i = 0; i < size; ++i) {
uintptr_t addr = baseAddr + i * step;
while (addr) {
uint32_t next = 0;
if (!ReadValue(hProcess, addr, "uint", &next)) break;
if (next != 1) nodes.push_back(addr);
addr = next & ~1u;
}
}
for (auto node : nodes) {
uintptr_t ent = GetAddress(hProcess, node, {0x10, 0xC4, 0x4, 0x0});
if (!ent) continue;
uintptr_t nameAddr = GetAddress(hProcess, ent, {0x58, 0x64, 0x0});
auto name = ReadString(hProcess, nameAddr, 96);
if (name.empty()) continue;
uintptr_t posAddr = GetAddress(hProcess, ent, {0x58, 0xC4, 0x4, 0x80});
float x=0,y=0,z=0;
ReadValue(hProcess, posAddr, "float", &x);
ReadValue(hProcess, posAddr+4, "float", &y);
ReadValue(hProcess, posAddr+8, "float", &z);
float scale = 0;
ReadValue(hProcess, posAddr+0x74, "float", &scale);
int level = 0;
uintptr_t lvlAddr = GetAddress(hProcess, ent, {0x58, 0xC4, 0x54, 0x120});
ReadValue(hProcess, lvlAddr, "int", &level);
int death = 0;
uintptr_t deathAddr = GetAddress(hProcess, ent, {0x58, 0x0});
ReadValue(hProcess, deathAddr, "int", &death);
double health = 0;
uintptr_t healthAddr = GetAddress(hProcess, ent, {0x58, 0xC4, 0x84, 0x80});
ReadValue(hProcess, healthAddr, "double", &health);
entities.push_back({name, x, y, z, scale, level, death, health});
}
std::cout << "\n[Info] Base: 0x" << std::hex << baseAddr << " Size: " << std::dec << size << " Step: " << step << std::endl;
std::cout << "[Info] Total entities found: " << entities.size() << std::endl;
return entities;
}
DWORD GetPID(const std::wstring& name) {
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W e{sizeof(e)};
if (Process32FirstW(snap, &e)) do {} while (Process32NextW(snap, &e) && name != e.szExeFile);
CloseHandle(snap);
return name == e.szExeFile ? e.th32ProcessID : 0;
}
std::tuple<float, float, float> GetForwardVector(float sx, float sy, float sz, float dx, float dy, float dz) {
float vx = dx - sx;
float vy = dy - sy;
float vz = dz - sz;
float length = sqrt(vx * vx + vy * vy + vz * vz);
if (length == 0) return {0.0f, 0.0f, 0.0f};
return {vx / length, vy / length, vz / length};
}
bool ContainsKeyword(const std::string& str, const std::vector<std::string>& keywords) {
for (const auto& kw : keywords) {
if (str.find(kw) != std::string::npos) return true;
}
return false;
}
// Silent Aim variables
std::array<uintptr_t, 3> allocatedSilentAimAddresses = {0, 0, 0};
std::array<std::vector<BYTE>, 3> originalInstructions;
std::array<uintptr_t, 3> instructionAddresses;
bool AllocateRemoteFloats(HANDLE hProcess) {
for (int i = 0; i < 3; i++) {
void* addr = VirtualAllocEx(hProcess, nullptr, sizeof(float), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!addr) {
std::cerr << "Allocation failed at index " << i << std::endl;
return false;
}
allocatedSilentAimAddresses[i] = reinterpret_cast<uintptr_t>(addr);
std::cout << "Allocated memory at: 0x" << std::hex << allocatedSilentAimAddresses[i] << std::endl;
}
return true;
}
bool ReadBytes(HANDLE hProcess, uintptr_t address, BYTE* buffer, SIZE_T size) {
SIZE_T bytesRead;
return ReadProcessMemory(hProcess, (LPCVOID)address, buffer, size, &bytesRead) && bytesRead == size;
}
bool WriteBytes(HANDLE hProcess, uintptr_t address, BYTE* buffer, SIZE_T size) {
SIZE_T bytesWritten;
return WriteProcessMemory(hProcess, (LPVOID)address, buffer, size, &bytesWritten) && bytesWritten == size;
}
bool PatchMovssInstruction(HANDLE hProcess, int index, uintptr_t baseAddress) {
uintptr_t instrAddr = baseAddress + silentAimOffsets[index];
instructionAddresses[index] = instrAddr;
std::vector<BYTE> orig(8);
if (!ReadBytes(hProcess, instrAddr, orig.data(), 8)) {
std::cerr << "Failed to read original instruction at " << std::hex << instrAddr << std::endl;
return false;
}
originalInstructions[index] = orig;
// Patch bytes f3 0f 10 05 + 4 bytes relative address
BYTE patch[8] = { 0xF3, 0x0F, 0x10, 0x05 }; // movss instruction
uint32_t absAddr = static_cast<uint32_t>(allocatedSilentAimAddresses[index]); // Absolute address
memcpy(patch + 4, &absAddr, sizeof(absAddr)); // Write absolute address in bytes
if (!WriteBytes(hProcess, instrAddr, patch, 8)) {
std::cerr << "Failed to write patch at " << std::hex << instrAddr << std::endl;
return false;
}
std::cout << "Patched movss at 0x" << std::hex << instrAddr << " to point to 0x" << allocatedSilentAimAddresses[index] << std::endl;
return true;
}
void RestoreOriginalInstructions(HANDLE hProcess) {
for (int i = 0; i < 3; i++) {
if (!originalInstructions[i].empty() && instructionAddresses[i] != 0) {
WriteBytes(hProcess, instructionAddresses[i], originalInstructions[i].data(), originalInstructions[i].size());
std::cout << "Restored original instruction at 0x" << std::hex << instructionAddresses[i] << std::endl;
}
}
}
void FreeAllocatedMemory(HANDLE hProcess) {
for (int i = 0; i < 3; i++) {
if (allocatedSilentAimAddresses[i]) {
VirtualFreeEx(hProcess, (LPVOID)allocatedSilentAimAddresses[i], 0, MEM_RELEASE);
std::cout << "Freed memory at 0x" << std::hex << allocatedSilentAimAddresses[i] << std::endl;
allocatedSilentAimAddresses[i] = 0;
}
}
}
void WriteSilentAimVector(HANDLE hProcess, float fx, float fy, float fz) {
if (!allocatedSilentAimAddresses[0] || !allocatedSilentAimAddresses[1] || !allocatedSilentAimAddresses[2]) {
std::cerr << "Silent Aim addresses not allocated" << std::endl;
return;
}
std::cout << "Writing Silent Aim vector to addresses: "
<< std::hex
<< "X: 0x" << allocatedSilentAimAddresses[0] << " "
<< "Y: 0x" << allocatedSilentAimAddresses[1] << " "
<< "Z: 0x" << allocatedSilentAimAddresses[2] << std::dec << std::endl;
if (!WriteFloat(hProcess, allocatedSilentAimAddresses[0], -fx) ||
!WriteFloat(hProcess, allocatedSilentAimAddresses[1], -fy) ||
!WriteFloat(hProcess, allocatedSilentAimAddresses[2], -fz)) {
std::cerr << "Failed to write Silent Aim vector values" << std::endl;
}
}
int main() {
DWORD pid = GetPID(L"Trove.exe");
if (!pid) {
std::cerr << "Failed to find Trove.exe process." << std::endl;
return 1;
}
HANDLE proc = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!proc) {
std::cerr << "Failed to open Trove.exe process." << std::endl;
return 1;
}
HMODULE mods[1024]; DWORD needed;
EnumProcessModules(proc, mods, sizeof(mods), &needed);
uintptr_t base = reinterpret_cast<uintptr_t>(mods[0]);
if (!AllocateRemoteFloats(proc)) {
std::cerr << "Failed to allocate memory for Silent Aim" << std::endl;
CloseHandle(proc);
return 1;
}
for (int i = 0; i < 3; i++) {
if (!PatchMovssInstruction(proc, i, base)) {
std::cerr << "Failed to patch movss instruction" << std::endl;
RestoreOriginalInstructions(proc);
FreeAllocatedMemory(proc);
CloseHandle(proc);
return 1;
}
}
std::cout << "Silent Aim initialized successfully" << std::endl;
while (true) {
uintptr_t localPlayer = GetAddress(proc, base, {localPlayerOffset});
uintptr_t playerPosPtr = GetAddress(proc, base, positionOffsets);
uintptr_t camPtr = GetAddress(proc, base, camOffsets);
uintptr_t world = GetAddress(proc, base, {0x11F8514, 0x0});
auto allEntities = GetAllEntities(proc, world);
std::vector<Entity> filteredEntities;
for (const auto& e : allEntities) {
if (!ContainsKeyword(e.name, blacklist_keywords)) {
filteredEntities.push_back(e);
}
}
float px = ReadFloat(proc, playerPosPtr);
float py = ReadFloat(proc, playerPosPtr + 4);
float pz = ReadFloat(proc, playerPosPtr + 8);
float cx = ReadFloat(proc, camPtr);
float cy = ReadFloat(proc, camPtr + 4);
float cz = ReadFloat(proc, camPtr + 8);
// Print player and camera coordinates
std::cout << "[PlayerPos] x: " << px << ", y: " << py << ", z: " << pz << std::endl;
std::cout << "[CamPos] x: " << cx << ", y: " << cy << ", z: " << cz << std::endl;
float closestDist = FLT_MAX;
Entity closestEntity = {"", 0, 0, 0, 0, 0, 0, 0.0};
bool found = false;
for (const auto& e : filteredEntities) {
float dx = e.x - px;
float dy = e.y - py;
float dz = e.z - pz;
float dist = sqrt(dx * dx + dy * dy + dz * dz);
if (dist < closestDist && dist <= MAX_RANGE) {
closestDist = dist;
closestEntity = e;
found = true;
}
}
if (found) {
auto [fx, fy, fz] = GetForwardVector(cx, cy, cz, closestEntity.x, closestEntity.y, closestEntity.z);
WriteSilentAimVector(proc, fx, fy, fz);
std::cout << "[SilentAim] Target: " << closestEntity.name << " Vector: (" << fx << ", " << fy << ", " << fz << ") Distance: " << closestDist << std::endl;
} else {
std::cout << "No valid entity found for Silent Aim within range " << MAX_RANGE << ".\n";
}
Sleep(10);
}
RestoreOriginalInstructions(proc);
FreeAllocatedMemory(proc);
CloseHandle(proc);
return 0;
}
