-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexport.cpp
More file actions
151 lines (127 loc) · 5.25 KB
/
export.cpp
File metadata and controls
151 lines (127 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "export.h"
#include "PatchedFunctionData.h"
#include "function_patcher.h"
#include "utils/globals.h"
#include <mutex>
#include <ranges>
#include <vector>
#include <wums/exports.h>
WUT_CHECK_OFFSET(function_replacement_data_v2_t, 0x00, VERSION);
WUT_CHECK_OFFSET(function_replacement_data_v3_t, 0x00, version);
FunctionPatcherStatus FPAddFunctionPatch(function_replacement_data_t *function_data, PatchedFunctionHandle *outHandle, bool *outHasBeenPatched) {
if (function_data == nullptr) {
DEBUG_FUNCTION_LINE_ERR("function_data was NULL");
return FUNCTION_PATCHER_RESULT_INVALID_ARGUMENT;
}
if (function_data->version < 2 || function_data->version > 3) {
DEBUG_FUNCTION_LINE_ERR("Failed to patch function. struct version mismatch");
return FUNCTION_PATCHER_RESULT_UNSUPPORTED_STRUCT_VERSION;
}
std::optional<std::shared_ptr<PatchedFunctionData>> functionDataOpt;
if (function_data->version == 2) {
functionDataOpt = PatchedFunctionData::make_shared_v2(gFunctionAddressProvider, (function_replacement_data_v2_t *) function_data, gJumpHeapHandle);
} else if (function_data->version == 3) {
functionDataOpt = PatchedFunctionData::make_shared_v3(gFunctionAddressProvider, (function_replacement_data_v3_t *) function_data, gJumpHeapHandle);
} else {
// Should never happen.
DEBUG_FUNCTION_LINE_ERR("Unknown function_replacement_data_t struct version");
OSFatal("Unknown function patching struct version. Update FunctionPatcherModule/Aroma.");
}
if (!functionDataOpt) {
return FUNCTION_PATCHER_RESULT_UNKNOWN_ERROR;
}
auto &functionData = functionDataOpt.value();
// PatchFunction calls OSFatal on fatal errors.
// If this function returns false the target function was not patched
// Usually this means the target RPL is not (yet) loaded.
auto patchResult = PatchFunction(functionData);
if (outHasBeenPatched) {
*outHasBeenPatched = patchResult;
}
if (outHandle) {
*outHandle = functionData->getHandle();
}
{
std::lock_guard lock(gPatchedFunctionsMutex);
gPatchedFunctions.push_back(std::move(functionData));
OSMemoryBarrier();
}
return FUNCTION_PATCHER_RESULT_SUCCESS;
}
bool FunctionPatcherPatchFunction(function_replacement_data_t *function_data, PatchedFunctionHandle *outHandle) {
return FPAddFunctionPatch(function_data, outHandle, nullptr) == FUNCTION_PATCHER_RESULT_SUCCESS;
}
FunctionPatcherStatus FPRemoveFunctionPatch(PatchedFunctionHandle handle) {
std::lock_guard lock(gPatchedFunctionsMutex);
std::vector<std::shared_ptr<PatchedFunctionData>> toBeTempRestored;
bool found = false;
int32_t erasePosition = 0;
std::shared_ptr<PatchedFunctionData> toBeRemoved;
for (auto &cur : gPatchedFunctions) {
if (cur->getHandle() == handle) {
toBeRemoved = cur;
found = true;
if (!cur->isPatched) {
// Early return if the function is not patched.
break;
}
continue;
}
// Check if something else patched the same function afterwards.
if (found) {
if (cur->realPhysicalFunctionAddress == toBeRemoved->realPhysicalFunctionAddress) {
toBeTempRestored.push_back(cur);
}
} else {
erasePosition++;
}
}
if (!found) {
DEBUG_FUNCTION_LINE_ERR("Failed to find PatchedFunctionData by handle %08X", handle);
return FUNCTION_PATCHER_RESULT_PATCH_NOT_FOUND;
}
if (toBeRemoved->isPatched) {
// Restore function patches that were done after the patch we actually want to restore.
for (auto &cur : std::ranges::reverse_view(toBeTempRestored)) {
RestoreFunction(cur);
}
// Restore the function we actually want to restore
RestoreFunction(toBeRemoved);
}
gPatchedFunctions.erase(gPatchedFunctions.begin() + erasePosition);
if (toBeRemoved->isPatched) {
// Apply the other patches again
for (auto &cur : toBeTempRestored) {
PatchFunction(cur);
}
}
OSMemoryBarrier();
return FUNCTION_PATCHER_RESULT_SUCCESS;
}
bool FunctionPatcherRestoreFunction(PatchedFunctionHandle handle) {
return FPRemoveFunctionPatch(handle) == FUNCTION_PATCHER_RESULT_SUCCESS;
}
FunctionPatcherStatus FPGetVersion(FunctionPatcherAPIVersion *outVersion) {
if (outVersion == nullptr) {
return FUNCTION_PATCHER_RESULT_INVALID_ARGUMENT;
}
*outVersion = 2;
return FUNCTION_PATCHER_RESULT_SUCCESS;
}
FunctionPatcherStatus FPIsFunctionPatched(PatchedFunctionHandle handle, bool *outIsFunctionPatched) {
if (outIsFunctionPatched == nullptr) {
return FUNCTION_PATCHER_RESULT_INVALID_ARGUMENT;
}
std::lock_guard lock(gPatchedFunctionsMutex);
for (auto &cur : gPatchedFunctions) {
if (cur->getHandle() == handle) {
*outIsFunctionPatched = cur->isPatched;
return FUNCTION_PATCHER_RESULT_SUCCESS;
}
}
return FUNCTION_PATCHER_RESULT_PATCH_NOT_FOUND;
}
WUMS_EXPORT_FUNCTION(FPGetVersion);
WUMS_EXPORT_FUNCTION(FPAddFunctionPatch);
WUMS_EXPORT_FUNCTION(FPRemoveFunctionPatch);
WUMS_EXPORT_FUNCTION(FPIsFunctionPatched);