Skip to content

Commit 0c8ff15

Browse files
committed
Fixed freecam crash by changing hideHUD implementation to use modulePatches instead of midhooks. For reasons I don't understand the midhook jump table would be temporarily corrupted on construction, some of the time.
1 parent f56fed1 commit 0c8ff15

File tree

3 files changed

+92
-39
lines changed

3 files changed

+92
-39
lines changed

HCMInternal/HideHUD.cpp

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,11 @@ class HideHUDImplH1 : public GenericScopedServiceProvider
1111
private:
1212
GameState mGame;
1313

14-
static inline std::shared_ptr<ModuleMidHook> hideHUDFlagHook1;
15-
static inline std::shared_ptr< MidhookFlagInterpreter> hideHUDFlagInterpreter1;
16-
static void hideHUDFlagHookFunction1(SafetyHookContext& ctx) { hideHUDFlagInterpreter1->setFlag(ctx); }
14+
static inline std::shared_ptr<ModulePatch> hideHUDPatchHook1;
15+
static inline std::shared_ptr<ModulePatch> hideHUDPatchHook2;
16+
static inline std::shared_ptr<ModulePatch> hideHUDPatchHook3;
1717

1818

19-
static inline std::shared_ptr<ModuleMidHook> hideHUDFlagHook2;
20-
static inline std::shared_ptr< MidhookFlagInterpreter> hideHUDFlagInterpreter2;
21-
static void hideHUDFlagHookFunction2(SafetyHookContext& ctx) { hideHUDFlagInterpreter2->setFlag(ctx); }
22-
23-
24-
static inline std::shared_ptr<ModuleMidHook> hideHUDFlagHook3;
25-
static inline std::shared_ptr< MidhookFlagInterpreter> hideHUDFlagInterpreter3;
26-
static void hideHUDFlagHookFunction3(SafetyHookContext& ctx) { hideHUDFlagInterpreter3->setFlag(ctx); }
2719

2820
public:
2921
HideHUDImplH1(GameState gameImpl, IDIContainer& dicon)
@@ -32,27 +24,33 @@ class HideHUDImplH1 : public GenericScopedServiceProvider
3224
{
3325
auto ptr = dicon.Resolve<PointerManager>().lock();
3426

35-
auto hideHUDFlagFunction1 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDFlagFunction1), mGame);
36-
hideHUDFlagInterpreter1 = ptr->getData<std::shared_ptr<MidhookFlagInterpreter>>(nameof(hideHUDFlagInterpreter1), mGame);
37-
hideHUDFlagHook1 = ModuleMidHook::make(GameState(mGame).toModuleName(), hideHUDFlagFunction1, hideHUDFlagHookFunction1);
27+
auto hideHUDPatchFunction1 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDPatchFunction1), gameImpl);
28+
auto hideHUDPatchCode1 = ptr->getVectorData<byte>(nameof(hideHUDPatchCode1), gameImpl);
29+
hideHUDPatchHook1 = ModulePatch::make(gameImpl.toModuleName(), hideHUDPatchFunction1, *hideHUDPatchCode1.get());
3830

39-
auto hideHUDFlagFunction2 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDFlagFunction2), mGame);
40-
hideHUDFlagInterpreter2 = ptr->getData<std::shared_ptr<MidhookFlagInterpreter>>(nameof(hideHUDFlagInterpreter2), mGame);
41-
hideHUDFlagHook2 = ModuleMidHook::make(GameState(mGame).toModuleName(), hideHUDFlagFunction2, hideHUDFlagHookFunction2);
31+
auto hideHUDPatchFunction2 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDPatchFunction2), gameImpl);
32+
auto hideHUDPatchCode2 = ptr->getVectorData<byte>(nameof(hideHUDPatchCode2), gameImpl);
33+
hideHUDPatchHook2 = ModulePatch::make(gameImpl.toModuleName(), hideHUDPatchFunction2, *hideHUDPatchCode2.get());
34+
35+
auto hideHUDPatchFunction3 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDPatchFunction3), gameImpl);
36+
auto hideHUDPatchCode3 = ptr->getVectorData<byte>(nameof(hideHUDPatchCode3), gameImpl);
37+
hideHUDPatchHook3 = ModulePatch::make(gameImpl.toModuleName(), hideHUDPatchFunction3, *hideHUDPatchCode3.get());
4238

43-
auto hideHUDFlagFunction3 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDFlagFunction3), mGame);
44-
hideHUDFlagInterpreter3 = ptr->getData<std::shared_ptr<MidhookFlagInterpreter>>(nameof(hideHUDFlagInterpreter3), mGame);
45-
hideHUDFlagHook3 = ModuleMidHook::make(GameState(mGame).toModuleName(), hideHUDFlagFunction3, hideHUDFlagHookFunction3);
4639
}
4740

4841
virtual void updateService() override
4942
{
5043
// attach if requested
5144
PLOG_VERBOSE << "HideHUDImplH1::updateService";
5245
safetyhook::ThreadFreezer freezeThreads;
53-
hideHUDFlagHook1->setWantsToBeAttached(serviceIsRequested());
54-
hideHUDFlagHook2->setWantsToBeAttached(serviceIsRequested());
55-
hideHUDFlagHook3->setWantsToBeAttached(serviceIsRequested());
46+
Sleep(1);
47+
48+
49+
bool newState = serviceIsRequested();
50+
safetyhook::ThreadFreezer freeze{};
51+
hideHUDPatchHook1->setWantsToBeAttached(newState);
52+
hideHUDPatchHook2->setWantsToBeAttached(newState);
53+
hideHUDPatchHook3->setWantsToBeAttached(newState);
5654
PLOG_VERBOSE << "HideHUDImplH1::updateService DONE";
5755
}
5856
};
@@ -64,9 +62,9 @@ class HideHUDImplH2 : public GenericScopedServiceProvider
6462
private:
6563
GameState mGame;
6664

67-
static inline std::shared_ptr<ModuleMidHook> hideHUDFlagHook1;
68-
static inline std::shared_ptr< MidhookFlagInterpreter> hideHUDFlagInterpreter1;
69-
static void hideHUDFlagHookFunction1(SafetyHookContext& ctx) { hideHUDFlagInterpreter1->setFlag(ctx); }
65+
66+
static inline std::shared_ptr<ModulePatch> hideHUDPatchHook1;
67+
7068

7169

7270

@@ -77,18 +75,18 @@ class HideHUDImplH2 : public GenericScopedServiceProvider
7775
{
7876
auto ptr = dicon.Resolve<PointerManager>().lock();
7977

80-
auto hideHUDFlagFunction1 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDFlagFunction1), mGame);
81-
hideHUDFlagInterpreter1 = ptr->getData<std::shared_ptr<MidhookFlagInterpreter>>(nameof(hideHUDFlagInterpreter1), mGame);
82-
hideHUDFlagHook1 = ModuleMidHook::make(GameState(mGame).toModuleName(), hideHUDFlagFunction1, hideHUDFlagHookFunction1);
78+
auto hideHUDPatchFunction1 = ptr->getData<std::shared_ptr<MultilevelPointer>>(nameof(hideHUDPatchFunction1), gameImpl);
79+
auto hideHUDPatchCode1 = ptr->getVectorData<byte>(nameof(hideHUDPatchCode1), gameImpl);
80+
hideHUDPatchHook1 = ModulePatch::make(gameImpl.toModuleName(), hideHUDPatchFunction1, *hideHUDPatchCode1.get());
8381

8482
}
8583

8684
virtual void updateService() override
8785
{
8886
// attach if requested
8987
PLOG_VERBOSE << "HideHUDImplH2::updateService";
90-
safetyhook::ThreadFreezer freezeThreads;
91-
hideHUDFlagHook1->setWantsToBeAttached(serviceIsRequested());
88+
safetyhook::ThreadFreezer freezeThreads{};
89+
hideHUDPatchHook1->setWantsToBeAttached(serviceIsRequested());
9290
PLOG_VERBOSE << "HideHUDImplH2::updateService DONE";
9391
}
9492
};

HCMInternal/InternalPointerData.xml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,6 +4889,62 @@
48894889
</Version>
48904890
</VersionedEntry>
48914891

4892+
<VersionedEntry Name="hideHUDPatchFunction1" Type="MultilevelPointer::ModuleOffset">
4893+
<Version Version="1.3272.0.0" Game="Halo1">
4894+
<Module>halo1.dll</Module>
4895+
<Offsets>
4896+
<Offset>0xB31BA7</Offset>
4897+
</Offsets>
4898+
</Version>
4899+
4900+
<Version Version="1.3272.0.0" Game="Halo2">
4901+
<Module>halo2.dll</Module>
4902+
<Offsets>
4903+
<Offset>0x829053</Offset>
4904+
</Offsets>
4905+
</Version>
4906+
</VersionedEntry>
4907+
4908+
<VersionedEntry Name="hideHUDPatchFunction2" Type="MultilevelPointer::ModuleOffset">
4909+
<Version Version="1.3272.0.0" Game="Halo1">
4910+
<Module>halo1.dll</Module>
4911+
<Offsets>
4912+
<Offset>0xB12D8D</Offset>
4913+
</Offsets>
4914+
</Version>
4915+
</VersionedEntry>
4916+
4917+
<VersionedEntry Name="hideHUDPatchFunction3" Type="MultilevelPointer::ModuleOffset">
4918+
<Version Version="1.3272.0.0" Game="Halo1">
4919+
<Module>halo1.dll</Module>
4920+
<Offsets>
4921+
<Offset>0xB12E6C</Offset>
4922+
</Offsets>
4923+
</Version>
4924+
</VersionedEntry>
4925+
4926+
<VersionedEntry Name="hideHUDPatchCode1" Type="Vector" Typename="byte">
4927+
<Version Version="1.3272.0.0" Game="Halo1">
4928+
<Data>0x85</Data>
4929+
</Version>
4930+
4931+
<Version Version="1.3272.0.0" Game="Halo2">
4932+
<Data>0x85</Data>
4933+
</Version>
4934+
</VersionedEntry>
4935+
4936+
<VersionedEntry Name="hideHUDPatchCode2" Type="Vector" Typename="byte">
4937+
<Version Version="1.3272.0.0" Game="Halo1">
4938+
<Data>0x85</Data>
4939+
</Version>
4940+
</VersionedEntry>
4941+
4942+
<VersionedEntry Name="hideHUDPatchCode3" Type="Vector" Typename="byte">
4943+
<Version Version="1.3272.0.0" Game="Halo1">
4944+
<Data>0x75</Data>
4945+
</Version>
4946+
</VersionedEntry>
4947+
48924948

48934949
<!--<VersionedEntry Name="hideHUDContextFunction1" Type="MultilevelPointer::ModuleOffset">
48944950
<Version Version="1.3272.0.0" Game="Halo1">

HCMInternal/ModuleHook.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,6 @@ void ModuleMidHook::attach()
106106
PLOG_VERBOSE << "pOriginalFunction: " << std::hex << pOriginalFunction;
107107
PLOG_VERBOSE << "mHookFunction: " << std::hex << this->mHookFunction;
108108
PLOG_VERBOSE << "this->mMidhook: " << this->mMidHook.operator bool();
109-
// per https://github.com/cursey/safetyhook/commit/77243791d72bfe49b94349922710c443db1df0fa
110-
// mid hooks don't freeze the threads.
111-
// I don't know why they made this change (perhaps there's a good reason)
112-
// but to me it appears this would cause crashes with hooks that run frequently.
113-
// So we'll freeze the threads manually.
114-
115-
// as an aside.. I appear to be getting a rare crash around here. is attach being called before mHookFunction is necessarily created? how can I even debug for that..
116-
// and is that even something I can fix? might be a safetyhook issue. how is it even possible that the func is being called if threads are frozen tho?
117109

118110
safetyhook::ThreadFreezer freezeThreads;
119111
PLOG_VERBOSE << "threads frozen";
@@ -141,6 +133,8 @@ void ModuleMidHook::detach()
141133
return;
142134
}
143135

136+
safetyhook::ThreadFreezer freezeThreads;
137+
PLOG_VERBOSE << "threads frozen";
144138
this->mMidHook = {};
145139
PLOG_DEBUG << "successfully detached " << this->getAssociatedModule();
146140
}
@@ -171,6 +165,8 @@ void ModulePatch::attach()
171165

172166
logErrorReturn(currentBytes != mOriginalBytes, "Current bytes did not match original bytes");
173167

168+
safetyhook::ThreadFreezer freezeThreads;
169+
PLOG_VERBOSE << "threads frozen";
174170

175171
logErrorReturn(mOriginalFunction->writeArrayData(mPatchedBytes.data(), mPatchedBytes.size(), true) == false, std::format("Failed to patch new bytes: {}", MultilevelPointer::GetLastError()));
176172
}
@@ -190,6 +186,9 @@ void ModulePatch::detach()
190186

191187
logErrorReturn(currentBytes != mPatchedBytes, "Current bytes did not match patched bytes")
192188

189+
safetyhook::ThreadFreezer freezeThreads;
190+
PLOG_VERBOSE << "threads frozen";
191+
193192
logErrorReturn(mOriginalFunction->writeArrayData(mOriginalBytes.data(), mOriginalBytes.size(), true) == false, "Failed to restore original bytes");
194193

195194
}

0 commit comments

Comments
 (0)