#include <Windows.h>
#include <cstdint>
#include "offsets.hpp"
#include "client_dll.hpp"
#define ENTITY_ENTRY_SIZE 0x70
class PtrValidator {
private:
static constexpr size_t CACHE_SIZE = 4096;
struct CacheEntry {
void* base;
size_t region_size;
DWORD state;
DWORD protect;
DWORD time;
};
static CacheEntry cache[CACHE_SIZE];
static DWORD last_check;
static bool CheckAndCache(void* ptr) {
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(ptr, &mbi, sizeof(mbi)) == 0)
return false;
size_t index = (reinterpret_cast<uintptr_t>(ptr) >> 12) % CACHE_SIZE;
cache[index] = {
mbi.BaseAddress,
mbi.RegionSize,
mbi.State,
mbi.Protect,
GetTickCount()
};
return (mbi.State == MEM_COMMIT) &&
((mbi.Protect & PAGE_NOACCESS) == 0);
}
public:
static bool IsValidPtr(void* ptr) {
if (!ptr) return false;
size_t index = (reinterpret_cast<uintptr_t>(ptr) >> 12) % CACHE_SIZE;
auto& entry = cache[index];
DWORD current_time = GetTickCount();
if (entry.base &&
current_time - entry.time < 1000 &&
reinterpret_cast<uintptr_t>(ptr) >= reinterpret_cast<uintptr_t>(entry.base) &&
reinterpret_cast<uintptr_t>(ptr) < reinterpret_cast<uintptr_t>(entry.base) + entry.region_size) {
return (entry.state == MEM_COMMIT) &&
((entry.protect & PAGE_NOACCESS) == 0);
}
return CheckAndCache(ptr);
}
};
PtrValidator::CacheEntry PtrValidator::cache[CACHE_SIZE] = {};
DWORD PtrValidator::last_check = 0;
void glow(uint64_t current) {
if (!PtrValidator::IsValidPtr((void*)current)) return;
uint64_t glowBase = current + cs2_dumper::schemas::client_dll::C_BaseModelEntity::m_Glow;
if (!PtrValidator::IsValidPtr((void*)glowBase)) return;
uint64_t glowColorOverride = glowBase + cs2_dumper::schemas::client_dll::CGlowProperty::m_glowColorOverride;
uint64_t glowEnable = glowBase + cs2_dumper::schemas::client_dll::CGlowProperty::m_bGlowing;
if (!PtrValidator::IsValidPtr((void*)glowColorOverride) || !PtrValidator::IsValidPtr((void*)glowEnable)) return;
*(uint32_t*)(glowColorOverride) = 0x800000FF;
*(bool*)(glowEnable) = true;
}
DWORD WINAPI Main(LPVOID) {
while (true) {
uint64_t client_base = (uint64_t)GetModuleHandleA("client.dll");
if (!client_base) { Sleep(100); continue; }
uint64_t entity_list = *(uint64_t*)(client_base + cs2_dumper::offsets::client_dll::dwEntityList);
if (!entity_list) { Sleep(100); continue; }
uint64_t local = *(uint64_t*)(client_base + cs2_dumper::offsets::client_dll::dwLocalPlayerPawn);
if (!local) { Sleep(10); continue; }
uint8_t teamNum = *(uint8_t*)(local + cs2_dumper::schemas::client_dll::C_BaseEntity::m_iTeamNum);
for (int i = 0; i < 64; i++) {
uint64_t list_entry = *(uint64_t*)(entity_list + 0x10);
if (!list_entry) continue;
uint64_t controller = *(uint64_t*)(list_entry + 0x70 * (i & 0x1FF));
if (!controller) continue;
uint32_t pawnHandle = *(uint32_t*)(controller + cs2_dumper::schemas::client_dll::CCSPlayerController::m_hPlayerPawn);
if (!pawnHandle) continue;
uint64_t p_chunk = *(uint64_t*)(entity_list + 8 * ((pawnHandle & 0x7FFF) >> 9) + 0x10);
if (!p_chunk) continue;
uint64_t current_pawn = *(uint64_t*)(p_chunk + 0x70 * (pawnHandle & 0x1FF));
if (!current_pawn || current_pawn == local) continue;
int alive = *(int*)(current_pawn + cs2_dumper::schemas::client_dll::C_BaseEntity::m_lifeState);
if (alive != 256) continue;
uint8_t currentTeamNum = *(uint8_t*)(current_pawn + cs2_dumper::schemas::client_dll::C_BaseEntity::m_iTeamNum);
if (currentTeamNum != teamNum) {
glow(current_pawn);
}
}
Sleep(0);
}
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
CreateThread(nullptr, 0, Main, nullptr, 0, nullptr);
}
return TRUE;
}