-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathRemapClass.cpp
More file actions
129 lines (99 loc) · 4.59 KB
/
RemapClass.cpp
File metadata and controls
129 lines (99 loc) · 4.59 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
// RemapClass.cpp : By AlSch092 @ Github
// Thanks to changeofpace @ Github for original self-remapping-code example
// works for both x86 and x64
#include "RemapClass.hpp"
#pragma pack(push, 1) //disable padding for good measure...
class ProtectedClass
{
public:
UINT32 GameTickSpeed;
FLOAT GameEngineGravity;
BOOL Invincible;
ProtectedClass(UINT32 tickSpeed, FLOAT gravity, BOOL invincible)
: GameTickSpeed(tickSpeed), GameEngineGravity(gravity), Invincible(invincible) {}
void PrintMembers() const
{
printf("ProtectedClass.GameTickSpeed: %d\n", this->GameTickSpeed);
printf("ProtectedClass.GameEngineGravity: %f\n", this->GameEngineGravity);
printf("ProtectedClass.Invincible: %d\n", this->Invincible);
}
};
#pragma pack(pop)
class MappedMemory //RAII class to handle memory mapping
{
private:
HANDLE hSection;
PVOID pViewBase;
SIZE_T size;
public:
MappedMemory(SIZE_T sectionSize) : hSection(nullptr), pViewBase(nullptr), size(sectionSize)
{
LARGE_INTEGER sectionSizeLi = {};
sectionSizeLi.QuadPart = sectionSize;
NTSTATUS ntstatus = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, §ionSizeLi, PAGE_EXECUTE_READWRITE, SEC_COMMIT | SEC_NO_CHANGE, NULL);
if (!NT_SUCCESS(ntstatus))
{
throw std::runtime_error("NtCreateSection failed");
}
SIZE_T viewSize = 0;
LARGE_INTEGER sectionOffset = {};
ntstatus = NtMapViewOfSection(hSection, NtCurrentProcess(), &pViewBase, 0, PAGE_SIZE, §ionOffset, &viewSize, ViewUnmap, 0, PAGE_READWRITE);
if (!NT_SUCCESS(ntstatus))
{
CloseHandle(hSection);
throw std::runtime_error("NtMapViewOfSection failed");
}
printf("Viewbase at: %llX\n", (UINT64)pViewBase);
}
void Protect() //protect the memory to make it non-writable
{
SIZE_T viewSize = 0;
LARGE_INTEGER sectionOffset = {};
NTSTATUS ntstatus = NtUnmapViewOfSection(NtCurrentProcess(), pViewBase); // unmap original view
ntstatus = NtMapViewOfSection(hSection, NtCurrentProcess(), &pViewBase, 0, 0, §ionOffset, &viewSize, ViewUnmap, SEC_NO_CHANGE, PAGE_EXECUTE_READ); //map with SEC_NO_CHANGE
if (!NT_SUCCESS(ntstatus))
{
throw std::runtime_error("Failed to remap view as protected");
}
}
~MappedMemory() //RAII destructor - unmap view of section
{
if (hSection && hSection != INVALID_HANDLE_VALUE)
{
CloseHandle(hSection);
hSection = INVALID_HANDLE_VALUE; //since we call the destructor explicitly if modifying the protected classes values, make sure a "double closehandle" doesnt occur to avoid a thrown exception
}
if (pViewBase)
{
NtUnmapViewOfSection(NtCurrentProcess(), pViewBase);
}
}
PVOID GetBaseAddress() const
{
return pViewBase;
}
template<typename T, typename... Args> //"placement new" concept using variadic template
T* Construct(Args&&... args)
{
return new (pViewBase) T(std::forward<Args>(args)...);
}
};
int main()
{
const SIZE_T classSize = sizeof(ProtectedClass);
MappedMemory memory(classSize); //create the memory-mapped view and construct the object inside it using placement new
ProtectedClass* protTest = memory.Construct<ProtectedClass>(100, 500.0f, TRUE);
protTest->PrintMembers(); //print initialized values for the sake of showing that we can modify them later if needed by re-mapping
memory.Protect(); //protect the memory from further writes
printf("\n========= Example of modifying values (using a new instance) =========\n");
MappedMemory modifiedMemory(classSize); //create new instance and modify the values
ProtectedClass* protTestModified = modifiedMemory.Construct<ProtectedClass>(*protTest); //copy the original values
protTestModified->GameTickSpeed = 1337; //modify values in the new protected instance
protTestModified->GameEngineGravity = 123.0f;
memory.~MappedMemory(); //explicitly call destructor to unmap the original view
protTest = protTestModified; //reassign the original pointer to the modified view
modifiedMemory.Protect(); //protect the new instance
protTest->PrintMembers(); //print the modified values using the original pointer to give the illusion of being able to continue using the original pointer
system("pause");
return 0;
}