diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a30d25 --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ac801a --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# 🎡 CS2 External ESP + +Simple external esp using discord's overlay to render a box on top of cs2 highlighting your enemies and teammates including their health. + +## Video Showcase + +[![Cs2ESP](https://cdn.discordapp.com/attachments/903283950267564094/1148225159443005440/image.png)](https://youtu.be/SV_lddIxQ5w) +## 🌳 Simple Use + +1. Go to the [**releases**](https://github.com/IMXNOOBX/cs2-external-esp/releases) tab. +2. Find the latest release and download it +3. Open the binary file and cs2 (doesnt matter which one goes first) + +* ❗ You must have discord overlay enabled! Settings > Game Overlay > Enable +* ❗ Make sure you have enabled the overlay in for that game in Registered Games + +## 📘 Developer Instructions + +1. Build the program using Visual Studio 2022 + - Build: **`x64 - Release`** + +2. Locate your binary file in the folder `/`, e.g., `x64/Release`. + +* ❕ In case the offsets get outdated (Every game update), you could check UnnamedZ03's repository for the updated ones [here](https://github.com/UnnamedZ03/CS2-external-base/blob/58466cd7feba2fbcf5ab49b0dbbdc7bcd6d7df58/source/CSSPlayer.hpp#L3-L15) + +## 💫 Credits + +* SamuelTulach's [OverlayCord](https://github.com/SamuelTulach/OverlayCord) for making the discord overlay hijack. +* [UnnamedZ03](https://github.com/UnnamedZ03) for providing [offsets](https://www.unknowncheats.me/forum/3846642-post734.html) and guide with his [CS2-external-base](https://github.com/UnnamedZ03/CS2-external-base) +* Unknowncheats comunity for their reseach! diff --git a/cs2-external-esp.sln b/cs2-external-esp.sln new file mode 100644 index 0000000..e3e80eb --- /dev/null +++ b/cs2-external-esp.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33627.172 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory-external", "memory-external\memory-external.vcxproj", "{B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Debug|x64.ActiveCfg = Debug|x64 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Debug|x64.Build.0 = Debug|x64 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Debug|x86.ActiveCfg = Debug|Win32 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Debug|x86.Build.0 = Debug|Win32 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Release|x64.ActiveCfg = Release|x64 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Release|x64.Build.0 = Release|x64 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Release|x86.ActiveCfg = Release|Win32 + {B87AB66D-73CC-48A1-9D3A-76B2ECBD3A64}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {063DD42C-122E-4C4F-8197-C778238B160A} + EndGlobalSection +EndGlobal diff --git a/memory-external/classes/OverlayCord.h b/memory-external/classes/OverlayCord.h new file mode 100644 index 0000000..260e847 --- /dev/null +++ b/memory-external/classes/OverlayCord.h @@ -0,0 +1,174 @@ +/* + * https://github.com/SamuelTulach/OverlayCord + */ + +#ifndef OVERLAYCORD_H +#define OVERLAYCORD_H + +#include +#include +#include + +namespace OverlayCord +{ + namespace Communication + { + typedef struct _Header + { + UINT Magic; + UINT FrameCount; + UINT NoClue; + UINT Width; + UINT Height; + BYTE Buffer[1]; + } Header; + + typedef struct _ConnectedProcessInfo + { + UINT ProcessId; + HANDLE File; + Header* MappedAddress; + } ConnectedProcessInfo; + + inline bool ConnectToProcess(ConnectedProcessInfo& processInfo) + { + std::string mappedFilename = "DiscordOverlay_Framebuffer_Memory_" + std::to_string(processInfo.ProcessId); + processInfo.File = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, mappedFilename.c_str()); + if (!processInfo.File || processInfo.File == INVALID_HANDLE_VALUE) + return false; + + processInfo.MappedAddress = static_cast(MapViewOfFile(processInfo.File, FILE_MAP_ALL_ACCESS, 0, 0, 0)); + return processInfo.MappedAddress; + } + + inline void DisconnectFromProcess(ConnectedProcessInfo& processInfo) + { + UnmapViewOfFile(processInfo.MappedAddress); + processInfo.MappedAddress = nullptr; + + CloseHandle(processInfo.File); + processInfo.File = nullptr; + } + + inline void SendFrame(ConnectedProcessInfo& processInfo, UINT width, UINT height, void* frame, UINT size) + { + // frame is in B8G8R8A8 format + // size can be nearly anything since it will get resized + // for the screen appropriately, although the maximum size is + // game window width * height * 4 (BGRA) + processInfo.MappedAddress->Width = width; + processInfo.MappedAddress->Height = height; + + memcpy(processInfo.MappedAddress->Buffer, frame, size); + + processInfo.MappedAddress->FrameCount++; // this will cause the internal module to copy over the framebuffer + } + } + + namespace Drawing + { + typedef struct _Frame + { + UINT Width; + UINT Height; + UINT Size; + void* Buffer; + } Frame; + + typedef struct _Pixel + { + BYTE B, G, R, A; + } Pixel; + + inline Frame CreateFrame(UINT width, UINT height) + { + Frame output; + output.Width = width; + output.Height = height; + output.Size = width * height * 4; + + output.Buffer = malloc(output.Size); + memset(output.Buffer, 0, output.Size); + + return output; + } + + inline void CleanFrame(Frame& frame) + { + memset(frame.Buffer, 0, frame.Size); + } + + inline void SetPixel(Frame& frame, UINT x, UINT y, Pixel color) + { + if (x < frame.Width && y < frame.Height) + { + Pixel* buf = static_cast(frame.Buffer); + buf[y * frame.Width + x] = color; + } + } + + inline void DrawLine(Frame& frame, UINT x1, UINT y1, UINT x2, UINT y2, Pixel color) + { + int dx = abs(static_cast(x2 - x1)), sx = x1 < x2 ? 1 : -1; + int dy = -abs(static_cast(y2 - y1)), sy = y1 < y2 ? 1 : -1; + int err = dx + dy, e2; + + while (true) + { + SetPixel(frame, x1, y1, color); + if (x1 == x2 && y1 == y2) + break; + e2 = 2 * err; + if (e2 >= dy) { err += dy; x1 += sx; } + if (e2 <= dx) { err += dx; y1 += sy; } + } + } + + inline void DrawRectangle(Frame& frame, UINT x1, UINT y1, UINT width, UINT height, Pixel color) + { + for (UINT x = x1; x < x1 + width; x++) + { + SetPixel(frame, x, y1, color); + SetPixel(frame, x, y1 + height - 1, color); + } + + for (UINT y = y1; y < y1 + height; y++) + { + SetPixel(frame, x1, y, color); + SetPixel(frame, x1 + width - 1, y, color); + } + } + + inline void DrawCircle(Frame& frame, UINT x0, UINT y0, UINT radius, Pixel color) + { + int x = radius; + int y = 0; + int radiusError = 1 - x; + + while (x >= y) + { + SetPixel(frame, x0 + x, y0 + y, color); + SetPixel(frame, x0 - x, y0 + y, color); + SetPixel(frame, x0 - x, y0 - y, color); + SetPixel(frame, x0 + x, y0 - y, color); + SetPixel(frame, x0 + y, y0 + x, color); + SetPixel(frame, x0 - y, y0 + x, color); + SetPixel(frame, x0 - y, y0 - x, color); + SetPixel(frame, x0 + y, y0 - x, color); + + y++; + if (radiusError < 0) + { + radiusError += 2 * y + 1; + } + else + { + x--; + radiusError += 2 * (y - x + 1); + } + } + } + } +} + +#endif \ No newline at end of file diff --git a/memory-external/classes/vector.hpp b/memory-external/classes/vector.hpp new file mode 100644 index 0000000..414bf75 --- /dev/null +++ b/memory-external/classes/vector.hpp @@ -0,0 +1,105 @@ +#pragma once +#include +#include + +int screen_x = GetSystemMetrics(SM_CXSCREEN); +int screen_y = GetSystemMetrics(SM_CYSCREEN); + +struct view_matrix_t { + float* operator[ ](int index) { + return matrix[index]; + } + + float matrix[4][4]; +}; + +struct Vector3 +{ + // constructor + constexpr Vector3( + const float x = 0.f, + const float y = 0.f, + const float z = 0.f) noexcept : + x(x), y(y), z(z) { } + + // operator overloads + constexpr const Vector3& operator-(const Vector3& other) const noexcept + { + return Vector3{ x - other.x, y - other.y, z - other.z }; + } + + constexpr const Vector3& operator+(const Vector3& other) const noexcept + { + return Vector3{ x + other.x, y + other.y, z + other.z }; + } + + constexpr const Vector3& operator/(const float factor) const noexcept + { + return Vector3{ x / factor, y / factor, z / factor }; + } + + constexpr const Vector3& operator*(const float factor) const noexcept + { + return Vector3{ x * factor, y * factor, z * factor }; + } + + constexpr const bool operator>(const Vector3& other) const noexcept { + return x > other.x && y > other.y && z > other.z; + } + + constexpr const bool operator>=(const Vector3& other) const noexcept { + return x >= other.x && y >= other.y && z >= other.z; + } + + constexpr const bool operator<(const Vector3& other) const noexcept { + return x < other.x && y < other.y && z < other.z; + } + + constexpr const bool operator<=(const Vector3& other) const noexcept { + return x <= other.x && y <= other.y && z <= other.z; + } + + // utils + constexpr const Vector3& ToAngle() const noexcept + { + return Vector3{ + std::atan2(-z, std::hypot(x, y)) * (180.0f / std::numbers::pi_v), + std::atan2(y, x) * (180.0f / std::numbers::pi_v), + 0.0f }; + } + + float length() const { + return std::sqrt(x * x + y * y + z * z); + } + + float length2d() const { + return std::sqrt(x * x + y * y); + } + + constexpr const bool IsZero() const noexcept + { + return x == 0.f && y == 0.f && z == 0.f; + } + + Vector3 world_to_screen(view_matrix_t matrix) const { + float _x = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z + matrix[0][3]; + float _y = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z + matrix[1][3]; + + float w = matrix[3][0] * x + matrix[3][1] * y + matrix[3][2] * z + matrix[3][3]; + + float inv_w = 1.f / w; + _x *= inv_w; + _y *= inv_w; + + float x = screen_x * .5f; + float y = screen_y * .5f; + + x += 0.5f * _x * screen_x + 0.5f; + y -= 0.5f * _y * screen_y + 0.5f; + + return { x, y, w }; + } + + // struct data + float x, y, z; +}; \ No newline at end of file diff --git a/memory-external/main.cpp b/memory-external/main.cpp new file mode 100644 index 0000000..931e363 --- /dev/null +++ b/memory-external/main.cpp @@ -0,0 +1,159 @@ +#include +#include +#include + +#include "memory/memory.hpp" +#include "classes/vector.hpp" +#include "classes/OverlayCord.h" + +// https://www.unknowncheats.me/forum/3846642-post734.html + +#define dwLocalPlayer 0x1713348 +#define dwEntityList 0x1679C38 +#define dwPawnHealth 0x808 +#define dwPlayerPawn 0x5dc +#define dwViewMatrix 0x1713CF0 +#define m_iTeamNum 0x3bf +#define m_vecOrigin 0x12AC + +int main() { + std::shared_ptr process = std::make_shared(); + + std::cout << "[cs2] Waiting for cs2.exe..." << std::endl; + + while (!process->AttachProcess("cs2.exe")) + std::this_thread::sleep_for(std::chrono::seconds(1)); + + std::cout << "[cs2] Attached to cs2.exe" << std::endl; + + ProcessModule base_module; + + do { + base_module = process->GetModule("client.dll"); + if (base_module.base == 0) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "[cs2] Failed to find module client.dll" << std::endl; + } + } while (base_module.base == 0); + + std::cout << "[overlay] Connecting to the process..." << std::endl; + OverlayCord::Communication::ConnectedProcessInfo processInfo = { 0 }; + processInfo.ProcessId = process->pid_; + + bool status = false; + do { + status = OverlayCord::Communication::ConnectToProcess(processInfo); + if (!status) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "[overlay] Failed to connect to the process overlay backend" << std::endl; + } + } while (!status); + + std::cout << "[overlay] Connected to the process with mapped address 0x" << processInfo.MappedAddress << std::endl; + + OverlayCord::Drawing::Frame mainFrame = OverlayCord::Drawing::CreateFrame(screen_x, screen_y); + + OverlayCord::Drawing::Pixel enemy_color = { 75, 75, 175, 255 }; // BYTE B, G, R, A; + OverlayCord::Drawing::Pixel team_color = { 75, 175, 75, 255 }; + + std::cout << "[cs2] Fully set up, running main loop now" << std::endl; + + while (!(GetAsyncKeyState(VK_END) & 0x8000)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + uintptr_t localPlayer = process->read(base_module.base + dwLocalPlayer); + + if (!localPlayer) continue; + + int localTeam = process->read(localPlayer + m_iTeamNum); + + view_matrix_t view_matrix = process->read(base_module.base + dwViewMatrix); + + Vector3 localOrigin = process->read(localPlayer + m_vecOrigin); + + OverlayCord::Drawing::CleanFrame(mainFrame); + + uintptr_t entity_list = process->read(base_module.base + dwEntityList); + + for (int i = 1; i < 32; i++) { + uintptr_t list_entry = process->read(entity_list + (8 * (i & 0x7FFF) >> 9) + 16); + if (!list_entry) continue; + uintptr_t player = process->read(list_entry + 120 * (i & 0x1FF)); + + if (!player) continue; + + int playerHealth = process->read(player + dwPawnHealth); + if (playerHealth < 0 || playerHealth > 100) continue; + + int playerTeam = process->read(player + m_iTeamNum); + + // https://github.com/UnnamedZ03/CS2-external-base/blob/main/source/CSSPlayer.hpp#L132 + std::uint32_t playerpawn = process->read(player + dwPlayerPawn); + + uintptr_t list_entry2 = process->read(entity_list + 0x8 * ((playerpawn & 0x7FFF) >> 9) + 16); + if (!list_entry2) continue; + uintptr_t pCSPlayerPawn = process->read(list_entry2 + 120 * (playerpawn & 0x1FF)); + + if (pCSPlayerPawn == localPlayer) continue; + + // https://github.com/UnnamedZ03/CS2-external-base/blob/main/source/CSSPlayer.hpp#L132 + Vector3 origin = process->read(pCSPlayerPawn + m_vecOrigin); + + //if ((localOrigin - origin).length2d() > 1000) continue; + + Vector3 head; + head.x = origin.x; + head.y = origin.y; + head.z = origin.z + 75.f; + + Vector3 screenpos = origin.world_to_screen(view_matrix); + Vector3 screenhead = head.world_to_screen(view_matrix); + + float height = screenpos.y - screenhead.y; + float width = height / 2.4f; + if (screenpos.z >= 0.01f) { + OverlayCord::Drawing::Pixel health_color = { 75, + (unsigned char)(55 + playerHealth * 2), + (unsigned char)(255 - playerHealth), + 255 + }; + + OverlayCord::Drawing::DrawRectangle( + mainFrame, + screenhead.x - 25.f, + screenhead.y, + width, + height, + (localTeam == playerTeam ? team_color : enemy_color) + ); + + OverlayCord::Drawing::DrawRectangle( + mainFrame, + screenhead.x - 30.f, + screenhead.y + (height * (100 - playerHealth) / 100), + 2, + height - (height * (100 - playerHealth) / 100), + health_color + ); + } + } + + for (int i = 0; i < 10; i++) + OverlayCord::Drawing::DrawCircle(mainFrame, 15, 15, i, enemy_color); + + OverlayCord::Communication::SendFrame(processInfo, mainFrame.Width, mainFrame.Height, mainFrame.Buffer, mainFrame.Size); + } + + std::cout << "[overlay] Cleaning frame" << std::endl; + OverlayCord::Drawing::CleanFrame(mainFrame); + std::cout << "[overlay] Disconnecting from process" << std::endl; + OverlayCord::Communication::DisconnectFromProcess(processInfo); + + std::cout << "[cs2] Deataching from process" << std::endl; + process->Close(); + + std::cout << "[cs2] Press any key to close" << std::endl; + std::cin.get(); + + return 1; +} diff --git a/memory-external/memory-external.vcxproj b/memory-external/memory-external.vcxproj new file mode 100644 index 0000000..bafb9b6 --- /dev/null +++ b/memory-external/memory-external.vcxproj @@ -0,0 +1,144 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {b87ab66d-73cc-48a1-9d3a-76b2ecbd3a64} + memoryexternal + 10.0 + cs2-external-esp + + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + + + Console + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/memory-external/memory-external.vcxproj.filters b/memory-external/memory-external.vcxproj.filters new file mode 100644 index 0000000..9e25558 --- /dev/null +++ b/memory-external/memory-external.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/memory-external/memory/memory.cpp b/memory-external/memory/memory.cpp new file mode 100644 index 0000000..7c1fe0d --- /dev/null +++ b/memory-external/memory/memory.cpp @@ -0,0 +1,213 @@ +#include "memory.hpp" +#include + +uint32_t pProcess::FindProcessIdByProcessName(const char* ProcessName) +{ + std::wstring wideProcessName; + int wideCharLength = MultiByteToWideChar(CP_UTF8, 0, ProcessName, -1, nullptr, 0); + if (wideCharLength > 0) + { + wideProcessName.resize(wideCharLength); + MultiByteToWideChar(CP_UTF8, 0, ProcessName, -1, &wideProcessName[0], wideCharLength); + } + + HANDLE hPID = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + PROCESSENTRY32W process_entry_{ }; + process_entry_.dwSize = sizeof(PROCESSENTRY32W); + + DWORD pid = 0; + if (Process32FirstW(hPID, &process_entry_)) + { + do + { + if (!wcscmp(process_entry_.szExeFile, wideProcessName.c_str())) + { + pid = process_entry_.th32ProcessID; + break; + } + } while (Process32NextW(hPID, &process_entry_)); + } + CloseHandle(hPID); + return pid; +} + +uint32_t pProcess::FindProcessIdByWindowName(const char* WindowName) +{ + DWORD process_id = 0; + HWND windowHandle = FindWindowA(nullptr, WindowName); + if (windowHandle) + GetWindowThreadProcessId(windowHandle, &process_id); + return process_id; +} + +HWND pProcess::GetWindowHandleFromProcessId(DWORD ProcessId) { + HWND hwnd = NULL; + do { + hwnd = FindWindowEx(NULL, hwnd, NULL, NULL); + DWORD pid = 0; + GetWindowThreadProcessId(hwnd, &pid); + if (pid == ProcessId) { + TCHAR windowTitle[MAX_PATH]; + GetWindowText(hwnd, windowTitle, MAX_PATH); + if (IsWindowVisible(hwnd) && windowTitle[0] != '\0') { + return hwnd; + } + } + } while (hwnd != NULL); + return NULL; // No main window found for the given process ID +} + +bool pProcess::AttachProcess(const char* ProcessName) +{ + this->pid_ = this->FindProcessIdByProcessName(ProcessName); + + if (pid_) + { + HMODULE modules[0xFF]; + MODULEINFO module_info; + DWORD _; + + handle_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid_); + + EnumProcessModulesEx(this->handle_, modules, sizeof(modules), &_, LIST_MODULES_64BIT); + base_module_.base = (uintptr_t)modules[0]; + + GetModuleInformation(this->handle_, modules[0], &module_info, sizeof(module_info)); + base_module_.size = module_info.SizeOfImage; + + hwnd_ = this->GetWindowHandleFromProcessId(pid_); + + return true; + } + + return false; +} + +bool pProcess::AttachWindow(const char* WindowName) +{ + this->pid_ = this->FindProcessIdByWindowName(WindowName); + + if (pid_) + { + HMODULE modules[0xFF]; + MODULEINFO module_info; + DWORD _; + + handle_ = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid_); + + EnumProcessModulesEx(this->handle_, modules, sizeof(modules), &_, LIST_MODULES_64BIT); + base_module_.base = (uintptr_t)modules[0]; + + GetModuleInformation(this->handle_, modules[0], &module_info, sizeof(module_info)); + base_module_.size = module_info.SizeOfImage; + + hwnd_ = this->GetWindowHandleFromProcessId(pid_); + + return true; + } + return false; +} + +ProcessModule pProcess::GetModule(const char* lModule) +{ + std::wstring wideModule; + int wideCharLength = MultiByteToWideChar(CP_UTF8, 0, lModule, -1, nullptr, 0); + if (wideCharLength > 0) + { + wideModule.resize(wideCharLength); + MultiByteToWideChar(CP_UTF8, 0, lModule, -1, &wideModule[0], wideCharLength); + } + + HANDLE handle_module = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid_); + MODULEENTRY32W module_entry_{}; + module_entry_.dwSize = sizeof(MODULEENTRY32W); + + do + { + if (!wcscmp(module_entry_.szModule, wideModule.c_str())) + { + CloseHandle(handle_module); + return { (DWORD_PTR)module_entry_.modBaseAddr, module_entry_.dwSize }; + } + } while (Module32NextW(handle_module, &module_entry_)); + + CloseHandle(handle_module); + return { 0, 0 }; +} + +LPVOID pProcess::Allocate(size_t size_in_bytes) +{ + return VirtualAllocEx(this->handle_, NULL, size_in_bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +} + +uintptr_t pProcess::FindSignature(std::vector signature) +{ + std::unique_ptr data; + data = std::make_unique(this->base_module_.size); + + if (!ReadProcessMemory(this->handle_, (void*)(this->base_module_.base), data.get(), this->base_module_.size, NULL)) { + return 0x0; + } + + for (uintptr_t i = 0; i < this->base_module_.size; i++) + { + for (uintptr_t j = 0; j < signature.size(); j++) + { + if (signature.at(j) == 0x00) + continue; + + if (*reinterpret_cast(reinterpret_cast(&data[i + j])) == signature.at(j)) + { + if (j == signature.size() - 1) + return this->base_module_.base + i; + continue; + } + break; + } + } + return 0x0; +} + +uintptr_t pProcess::FindSignature(ProcessModule target_module, std::vector signature) +{ + std::unique_ptr data; + data = std::make_unique(0xFFFFFFF); + + if (!ReadProcessMemory(this->handle_, (void*)(target_module.base), data.get(), 0xFFFFFFF, NULL)) { + return NULL; + } + + for (uintptr_t i = 0; i < 0xFFFFFFF; i++) + { + for (uintptr_t j = 0; j < signature.size(); j++) + { + if (signature.at(j) == 0x00) + continue; + + if (*reinterpret_cast(reinterpret_cast(&data[i + j])) == signature.at(j)) + { + if (j == signature.size() - 1) + return this->base_module_.base + i; + continue; + } + break; + } + } + return 0x0; +} + +uintptr_t pProcess::FindCodeCave(uint32_t length_in_bytes) +{ + std::vector cave_pattern = {}; + + for (uint32_t i = 0; i < length_in_bytes; i++) { + cave_pattern.push_back(0x00); + } + + return FindSignature(cave_pattern); +} + +void pProcess::Close() +{ + CloseHandle(handle_); +} \ No newline at end of file diff --git a/memory-external/memory/memory.hpp b/memory-external/memory/memory.hpp new file mode 100644 index 0000000..66ddc92 --- /dev/null +++ b/memory-external/memory/memory.hpp @@ -0,0 +1,101 @@ +#ifndef _PPROCESS_HPP_ +#define _PPROCESS_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +struct ProcessModule +{ + uintptr_t base, size; +}; + +class pProcess +{ +public: + DWORD pid_; // process id + HANDLE handle_; // handle to process + HWND hwnd_; // window handle + ProcessModule base_module_; + +public: + bool AttachProcess(const char* process_name); + bool AttachWindow(const char* window_name); + void Close(); + +public: + ProcessModule GetModule(const char* module_name); + LPVOID Allocate(size_t size_in_bytes); + uintptr_t FindCodeCave(uint32_t length_in_bytes); + uintptr_t FindSignature(std::vector signature); + uintptr_t FindSignature(ProcessModule target_module, std::vector signature); + + template + uintptr_t ReadOffsetFromSignature(std::vector signature, uint8_t offset) // offset example: "FF 05 ->22628B01<-" offset is 2 + { + uintptr_t pattern_address = this->FindSignature(signature); + if (!pattern_address) + return 0x0; + + T offset_value = this->read(pattern_address + offset); + return pattern_address + offset_value + offset + sizeof(T); + } + + bool read_raw(uintptr_t address, void* buffer, size_t size) + { + SIZE_T bytesRead; + if (ReadProcessMemory(this->handle_, reinterpret_cast(address), buffer, size, &bytesRead)) + { + return bytesRead == size; + } + return false; + } + + template + void write(uintptr_t address, T value) + { + WriteProcessMemory(handle_, (void*)address, &value, sizeof(T), 0); + } + + template + T read(uintptr_t address) + { + T buffer{}; + ReadProcessMemory(handle_, (void*)address, &buffer, sizeof(T), 0); + return buffer; + } + + void write_bytes(uintptr_t addr, std::vector patch) + { + WriteProcessMemory(handle_, (void*)addr, &patch[0], patch.size(), 0); + } + + uintptr_t read_multi_address(uintptr_t ptr, std::vector offsets) + { + uintptr_t buffer = ptr; + for (int i = 0; i < offsets.size(); i++) + buffer = this->read(buffer + offsets[i]); + + return buffer; + } + + template + T read_multi(uintptr_t base, std::vector offsets) { + uintptr_t buffer = base; + for (int i = 0; i < offsets.size() - 1; i++) + { + buffer = this->read(buffer + offsets[i]); + } + return this->read(buffer + offsets.back()); + } + +private: + uint32_t FindProcessIdByProcessName(const char* process_name); + uint32_t FindProcessIdByWindowName(const char* window_name); + HWND GetWindowHandleFromProcessId(DWORD ProcessId); +}; +#endif \ No newline at end of file