44#include " log.hpp"
55#include " memhlp.hpp"
66#include " patterns.hpp"
7+ #include " sdk/IClientUser.hpp"
78#include " vftableinfo.hpp"
89
910#include " libmem/libmem.h"
@@ -43,11 +44,11 @@ VFTHook<T>::VFTHook(const char* name) : Hook<T>::Hook(name)
4344}
4445
4546template <typename T>
46- bool DetourHook<T>::setup(const char * pattern, const MemHlp::SigFollowMode followMode, T hookFn)
47+ bool DetourHook<T>::setup(const char * pattern, const MemHlp::SigFollowMode followMode, lm_byte_t * extraData, lm_size_t extraDataSize, T hookFn)
4748{
4849 // Hardcoding g_modSteamClient here is definitely bad design, but we can easily change that
4950 // in case we ever need to
50- lm_address_t oFn = MemHlp::searchSignature (this ->name .c_str (), pattern, g_modSteamClient, followMode);
51+ lm_address_t oFn = MemHlp::searchSignature (this ->name .c_str (), pattern, g_modSteamClient, followMode, extraData, extraDataSize );
5152 if (oFn == LM_ADDRESS_BAD)
5253 {
5354 return false ;
@@ -59,6 +60,12 @@ bool DetourHook<T>::setup(const char* pattern, const MemHlp::SigFollowMode follo
5960 return true ;
6061}
6162
63+ template <typename T>
64+ bool DetourHook<T>::setup(const char * pattern, const MemHlp::SigFollowMode followMode, T hookFn)
65+ {
66+ return setup (pattern, followMode, nullptr , 0 , hookFn);
67+ }
68+
6269template <typename T>
6370void DetourHook<T>::place()
6471{
@@ -159,15 +166,32 @@ static bool hkCheckAppOwnership(void* a0, uint32_t appId, CAppOwnershipInfo* pOw
159166 return ret;
160167 }
161168
169+ const u_int32_t denuvoOwner = g_config.getDenuvoGameOwner (appId);
170+ // Do not modify Denuvo enabled Games
171+ if (!g_config.denuvoSpoof && denuvoOwner && denuvoOwner != g_currentSteamId)
172+ {
173+ // Would love to log the SteamId, but for users anonymity I won't
174+ g_pLog->once (" Skipping %u because it's a Denuvo game from someone else\n " , appId);
175+ return ret;
176+ }
177+
162178 if (g_config.isAddedAppId (appId) || (g_config.playNotOwnedGames && !pOwnershipInfo->purchased ))
163179 {
164- // Changing the purchased field is enough, but just for nicety in the Steamclient UI we change the owner too
165- pOwnershipInfo->ownerSteamId = g_currentSteamId;
166- pOwnershipInfo->purchased = true ;
180+ if (!denuvoOwner || denuvoOwner == g_currentSteamId)
181+ {
182+ // Changing the purchased field is enough, but just for nicety in the Steamclient UI we change the owner too
183+ pOwnershipInfo->ownerSteamId = g_currentSteamId;
184+ pOwnershipInfo->familyShared = false ;
185+ }
186+ else if (denuvoOwner)
187+ {
188+ pOwnershipInfo->ownerSteamId = denuvoOwner;
189+ pOwnershipInfo->familyShared = true ;
190+ }
167191
192+ pOwnershipInfo->purchased = true ;
168193 // Unnessecary but whatever
169194 pOwnershipInfo->permanent = true ;
170- pOwnershipInfo->familyShared = false ;
171195
172196 // Found in backtrace
173197 pOwnershipInfo->releaseState = 4 ;
@@ -180,7 +204,7 @@ static bool hkCheckAppOwnership(void* a0, uint32_t appId, CAppOwnershipInfo* pOw
180204
181205 // Doing that might be not worth it since this will most likely be easier to mantain
182206 // TODO: Backtrace those 4 calls and only patch the really necessary ones since this might be prone to breakage
183- if (g_config.disableFamilyLock && appIdOwnerOverride.count (appId) && appIdOwnerOverride.at (appId) < 4 )
207+ if (!denuvoOwner && g_config.disableFamilyLock && appIdOwnerOverride.count (appId) && appIdOwnerOverride.at (appId) < 4 )
184208 {
185209 pOwnershipInfo->ownerSteamId = 1 ; // Setting to "arbitrary" steam Id instead of own, otherwise bypass won't work for own games
186210 // Unnessecarry again, but whatever
@@ -384,6 +408,20 @@ static uint32_t hkClientUser_GetSubscribedApps(void* pClientUser, uint32_t* pApp
384408 return count;
385409}
386410
411+ static bool hkClientUser_RequiresLegacyCDKey (void * pClientUser, uint32_t appId, uint32_t * a2)
412+ {
413+ const bool requiresKey = Hooks::IClientUser_RequiresLegacyCDKey.tramp .fn (pClientUser, appId, a2);
414+ g_pLog->once (" IClientUser::RequiresLegacyCDKey(%p, %u, %u) -> %i\n " , pClientUser, appId, a2, requiresKey);
415+
416+ if (requiresKey && g_config.isAddedAppId (appId))
417+ {
418+ g_pLog->once (" Disable CD Key for %u\n " , appId);
419+ return false ;
420+ }
421+
422+ return requiresKey;
423+ }
424+
387425static void patchRetn (lm_address_t address)
388426{
389427 constexpr lm_byte_t retn = 0xC3 ;
@@ -480,6 +518,7 @@ namespace Hooks
480518 DetourHook<IClientApps_PipeLoop_t> IClientApps_PipeLoop (" IClientApps::PipeLoop" );
481519 DetourHook<IClientUser_BIsSubscribedApp_t> IClientUser_BIsSubscribedApp (" IClientUser::BIsSubscribedApp" );
482520 DetourHook<IClientUser_GetSubscribedApps_t> IClientUser_GetSubscribedApps (" IClientUser::GetSubscribedApps" );
521+ DetourHook<IClientUser_RequiresLegacyCDKey_t> IClientUser_RequiresLegacyCDKey (" IClientUser::RequiresLegacyCDKey" );
483522
484523 VFTHook<IClientAppManager_BIsDlcEnabled_t> IClientAppManager_BIsDlcEnabled (" IClientAppManager::BIsDlcEnabled" );
485524 VFTHook<IClientAppManager_LaunchApp_t> IClientAppManager_LaunchApp (" IClientAppManager::LaunchApp" );
@@ -496,8 +535,33 @@ bool Hooks::setup()
496535
497536 IClientUser_GetSteamId = MemHlp::searchSignature (" IClientUser::GetSteamId" , Patterns::GetSteamId, g_modSteamClient, MemHlp::SigFollowMode::Relative);
498537
499- lm_address_t runningApp = MemHlp::searchSignature (" RunningApp" , Patterns::FamilyGroupRunningApp, g_modSteamClient, MemHlp::SigFollowMode::Relative);
500- lm_address_t stopPlayingBorrowedApp = MemHlp::searchSignature (" StopPlayingBorrowedApp" , Patterns::StopPlayingBorrowedApp, g_modSteamClient, MemHlp::SigFollowMode::PrologueUpwards);
538+ lm_address_t runningApp = MemHlp::searchSignature (" RnningApp" , Patterns::FamilyGroupRunningApp, g_modSteamClient, MemHlp::SigFollowMode::Relative);
539+
540+ auto prologue = std::vector<lm_byte_t >({
541+ 0x56 , 0x57 , 0xe5 , 0x89 , 0x55
542+ });
543+ lm_address_t stopPlayingBorrowedApp = MemHlp::searchSignature
544+ (
545+ " StopPlayingBorrowedApp" ,
546+ Patterns::StopPlayingBorrowedApp,
547+ g_modSteamClient,
548+ MemHlp::SigFollowMode::PrologueUpwards,
549+ &prologue[0 ],
550+ prologue.size ()
551+ );
552+
553+ // TODO: Make this shit less verbose in case I fail my reversing & refactor for all this crap
554+ prologue = std::vector<lm_byte_t >({
555+ 0x53 , 0x56 , 0x57 , 0x55
556+ });
557+ bool requiresLegacyCDKey = IClientUser_RequiresLegacyCDKey.setup
558+ (
559+ Patterns::RequiresLegacyCDKey,
560+ MemHlp::SigFollowMode::PrologueUpwards,
561+ &prologue[0 ],
562+ prologue.size (),
563+ &hkClientUser_RequiresLegacyCDKey
564+ );
501565
502566 bool succeeded =
503567 CheckAppOwnership.setup (Patterns::CheckAppOwnership, MemHlp::SigFollowMode::Relative, &hkCheckAppOwnership)
@@ -509,7 +573,9 @@ bool Hooks::setup()
509573
510574 && runningApp != LM_ADDRESS_BAD
511575 && stopPlayingBorrowedApp != LM_ADDRESS_BAD
512- && IClientUser_GetSteamId != LM_ADDRESS_BAD;
576+ && IClientUser_GetSteamId != LM_ADDRESS_BAD
577+
578+ && requiresLegacyCDKey;
513579
514580 if (!succeeded)
515581 {
@@ -538,6 +604,7 @@ void Hooks::place()
538604 IClientAppManager_PipeLoop.place ();
539605 IClientUser_BIsSubscribedApp.place ();
540606 IClientUser_GetSubscribedApps.place ();
607+ IClientUser_RequiresLegacyCDKey.place ();
541608
542609 createAndPlaceSteamIdHook ();
543610}
@@ -551,6 +618,7 @@ void Hooks::remove()
551618 IClientAppManager_PipeLoop.remove ();
552619 IClientUser_BIsSubscribedApp.remove ();
553620 IClientUser_GetSubscribedApps.remove ();
621+ IClientUser_RequiresLegacyCDKey.remove ();
554622
555623 // VFT Hooks
556624 IClientAppManager_BIsDlcEnabled.remove ();
0 commit comments