diff --git a/camera_patch.vcxproj b/camera_patch.vcxproj new file mode 100644 index 0000000..0d3e485 --- /dev/null +++ b/camera_patch.vcxproj @@ -0,0 +1,157 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + {a2c53563-46f5-4d87-903f-3f1f2fdb2deb} + + + + + + + + 16.0 + Win32Proj + {c15e6bb1-4a30-4d37-9b96-3fc80e58cd4b} + camerapatch + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + stdc17 + $(ProjectDir)core\include;%(AdditionalIncludeDirectories) + + + Console + true + + + + + Level3 + true + true + false + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + stdc17 + MultiThreaded + false + $(ProjectDir)core\include;%(AdditionalIncludeDirectories) + AnySuitable + Speed + true + true + + + Console + true + true + false + AsInvoker + + + + + + \ No newline at end of file diff --git a/core/dota_sdk.hpp b/core/dota_sdk.hpp new file mode 100644 index 0000000..d7c9c45 --- /dev/null +++ b/core/dota_sdk.hpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef std::uintptr_t( __fastcall* CDOTACamera__Init )( ); +typedef void( __fastcall* SetRenderingEnabled )( std::uintptr_t CParticleCollectionPtr, bool render ); + +class DefClass { +public: + blackbone::ProcessMemory* memory; + std::uintptr_t baseAddr; + + std::uintptr_t GetVF( unsigned short idx ) noexcept { + const auto VMTAddr = memory->Read( baseAddr ).result( ); + + return memory->Read( VMTAddr + idx * 8 ).result( ); + } +}; + +class CDOTA_ParticleManager : DefClass { +public: + CDOTA_ParticleManager( ) { + memory = nullptr; + baseAddr = NULL; + } + + CDOTA_ParticleManager( blackbone::ProcessMemory* memory, std::uintptr_t baseAddr ) { + this->memory = memory; + this->baseAddr = baseAddr; + } + + class NewParticleEffect : DefClass { + public: + NewParticleEffect( ) { + memory = nullptr; + baseAddr = NULL; + } + NewParticleEffect( blackbone::ProcessMemory* memory, std::uintptr_t baseAddr ) { + this->memory = memory; + this->baseAddr = baseAddr; + } + DefClass GetParticleCollection( ) { + auto partCollection = memory->Read( baseAddr + 0x20 ).result( ); + auto res = DefClass( memory, partCollection ); + if ( !baseAddr || !partCollection ) return DefClass( 0, 0 ); + return res; + } + }; + + class ParticleListItem : DefClass { + public: + ParticleListItem( ) { + memory = nullptr; + baseAddr = NULL; + } + ParticleListItem( blackbone::ProcessMemory* memory, std::uintptr_t baseAddr ) { + this->memory = memory; + this->baseAddr = baseAddr; + } + CDOTA_ParticleManager::NewParticleEffect GetNewParticleEffect( ) { + auto newPartEffect = memory->Read( baseAddr + 0x10 ).result( ); + if ( !newPartEffect || !baseAddr ) return CDOTA_ParticleManager::NewParticleEffect( 0, 0 ); + return CDOTA_ParticleManager::NewParticleEffect( memory, newPartEffect ); + } + }; + + + std::vector GetParticleLists( ) { + std::vector list; + auto particlesBase = memory->Read( baseAddr + 0x88 ).result( ); + const auto pCount = this->GetParticleCount( ) * 8; + for ( int idx = 0x0; idx < pCount; idx += 0x8 ) { + CDOTA_ParticleManager::ParticleListItem thisEffect( memory, memory->Read( particlesBase + idx ).result( )); + list.push_back( thisEffect ); + } + + return list; + } + + int GetParticleCount( ) { + return memory->Read( baseAddr + 0x80 ).result( ); + } +}; + +class CDOTA_Camera : DefClass { +public: + CDOTA_Camera( ) { + memory = nullptr; + baseAddr = NULL; + } + + CDOTA_Camera( blackbone::ProcessMemory* memory, std::uintptr_t baseAddr ) { + this->memory = memory; + this->baseAddr = baseAddr; + } + + void SetDistance( float distance ) noexcept { // 0x270 + memory->Write( baseAddr + 0x270, distance ); + } + + void SetFOWAmount( float amount ) // 0x70 + { + memory->Write( baseAddr + 0x70, amount ); + } + + auto GetDistance( ) noexcept { + return memory->Read( baseAddr + 0x270 ).result( ); + } + + auto GetFOWAmount( ) + { + return memory->Read( baseAddr + 0x70 ).result( ); + } + + void ToggleFog( ) { + const auto aGetFog = this->GetVF( 18 ); + const auto instructionBytes = memory->Read( aGetFog ).result( ); + + if ( instructionBytes == 0x83485708245c8948 ) { // not patched + + // 0x0F, 0x57, 0xC0 | xorps xmm0, xmm0 + // 0xC3 | ret + constexpr const char* bytePatch = "\x0F\x57\xC0\xC3"; + memory->Write( aGetFog, 4, bytePatch ); + // std::cout << "Fog instructions patched" << std::endl; + } + else if ( instructionBytes == 0x83485708c3c0570f ) { // already patched + + // 0x48, 0x89, 0x5C, 0x24, 0x08 | mov qword ptr ss:[rsp+8], rbx + // 0x57 | push rdi + constexpr const char* byteRestore = "\x48\x89\x5C\x24\x08\x57"; + memory->Write( aGetFog, 6, byteRestore ); + // std::cout << "Fog instructions restored" << std::endl; + } + else { + std::cout << "Error, unknown fog instructions: " << instructionBytes << std::endl; + std::system( "pause" ); + exit( 1 ); + } + } + + void ToggleMaxZFar( ) { + const auto aGetZFar = this->GetVF( 19 ); + const auto instructionBytes = memory->Read( aGetZFar ).result( ); + + if ( instructionBytes == 0x83485708245c8948 ) { // not patched + + // 0xB8, 0x50, 0x46, 0x00, 0x00 | mov eax, 18000 + // 0xF3, 0x0F, 0x2A, 0xC0 | cvtsi2ss xmm0, eax + // 0xC3 | ret + constexpr const char* bytePatch = "\xB8\x50\x46\x00\x00\xF3\x0F\x2A\xC0\xC3"; + memory->Write( aGetZFar, 10, bytePatch ); + //std::cout << "ZFar instructions patched" << std::endl; + } + else if ( instructionBytes == 0x2a0ff300004650b8 ) { // already patched + + // 0x48, 0x89, 0x5C, 0x24, 0x08 | mov qword ptr ss:[rsp+8], rbx + // 0x57 | push rdi + // 0x48, 0x83, 0xEC, 0x40 | sub rsp, 40 + constexpr const char* byteRestore = "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x40"; + memory->Write( aGetZFar, 10, byteRestore ); + //std::cout << "ZFar instructions restored" << std::endl; + } + } +}; \ No newline at end of file diff --git a/core/main.cpp b/core/main.cpp new file mode 100644 index 0000000..722d92a --- /dev/null +++ b/core/main.cpp @@ -0,0 +1,86 @@ +#include "dota_sdk.hpp" + +// bool showParticles = false; + +int main( ) +{ + blackbone::Process dota; + + if ( NT_SUCCESS( dota.Attach( L"dota2.exe" ) ) ) { + auto pClientModule = dota.modules( ).GetModule( L"client.dll" ); + auto& pDOTAMemory = dota.memory( ); + + if ( pClientModule ) { + std::cout << "Attached to dota2.exe " << std::endl; + std::vector search_result; + blackbone::PatternSearch aDOTACameraInit_Pattern{ "\x48\x83\xEC\x38\xE8\xCC\xCC\xCC\xCC\x48\x85\xC0\x74\x4D" }; + //blackbone::PatternSearch aDOTAParticleManager_Pattern{ xorstr_( "\xE8\xCC\xCC\xCC\xCC\x8B\x14\x9F" ) }; + + //aDOTAParticleManager_Pattern.SearchRemote( dota, 0xCC, pClientModule.get( )->baseAddress, pClientModule.get( )->size, search_result, 1 ); + //search_result[0] = search_result[0] + ( pDOTAMemory.Read( search_result[0] + 1 ).result( ) + 5 ); + //const auto pDOTAParticleManager = search_result[0] + ( pDOTAMemory.Read( search_result[0] + 3 ).result( ) + 7 ); + //search_result.clear( ); + + while ( 1 ) { + std::cout << "PID: " << std::dec << dota.pid( ) << std::endl << "client.dll base: " << (void*)pClientModule.get( )->baseAddress << std::endl; + aDOTACameraInit_Pattern.SearchRemote( dota, 0xCC, pClientModule.get( )->baseAddress, pClientModule.get( )->size, search_result, 1 ); + const auto aGetCamera = search_result[0]; + + if ( aGetCamera /* && pDOTAParticleManager */ ) { + std::cout << "=================================\n[0] Change camera distance\n[1] Patch ZFar\n[2] Toggle Fog\n=> "; + int act; + std::cin >> act; + blackbone::RemoteFunction pFN( dota, aGetCamera ); + if ( auto result = pFN.Call( ); result.success( ) && result.result( ) ) { + + CDOTA_Camera DOTACamera( &pDOTAMemory, result.result( ) ); + + if ( act == 0 ) { + float dist; + std::system( "cls" ); + std::cout << "=> "; + std::cin >> dist; + DOTACamera.SetDistance( dist ); + } + else if ( act == 1 ) { + DOTACamera.ToggleMaxZFar( ); + } + else if ( act == 2 ) { + DOTACamera.ToggleFog( ); + } + /*else if ( act == 3 ) { + showParticles = !showParticles; + auto addr = pDOTAMemory.Read( pDOTAParticleManager ).result( ); + CDOTA_ParticleManager ParticleManager( &pDOTAMemory, addr ); + + std::cout << addr << std::endl;; + auto particlesList = ParticleManager.GetParticleLists( ); + for ( auto& particle : particlesList ) { + if ( auto particleCollection = particle.GetNewParticleEffect( ).GetParticleCollection( ); particleCollection.baseAddr ) { + blackbone::RemoteFunction pFNRendering( dota, particle.GetNewParticleEffect( ).GetParticleCollection( ).GetVF( 95 ) ); + pFNRendering.Call( particleCollection.baseAddr, true ); + } + } + + } + else if ( act == 4 ) { + exit( 0 ); + }*/ + else exit( 0 ); + } + else { + std::cout << "CDOTACamera or SetRenderingEnabled not found" << std::endl; + std::system( "pause" ); + exit( 1 ); + } + } + std::system( "cls" ); + } + } + } + else { + std::cout << "dota2.exe not found" << std::endl; + std::system( "pause" ); + exit( 1 ); + } +} \ No newline at end of file