Skip to content

Commit 3cd33df

Browse files
committed
Add support to game image with crc32 6ea6d1ba
- Use direct syscalls to change memory protection options
1 parent 97e6e0a commit 3cd33df

File tree

9 files changed

+187
-14
lines changed

9 files changed

+187
-14
lines changed

RS_ASIO/NtProtectVirtualMemory.asm

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
IFNDEF RAX
2+
.MODEL FLAT, C
3+
ENDIF
4+
5+
.CODE
6+
7+
8+
NtProtectVirtualMemory PROC
9+
mov eax, 50h
10+
call KiSystemCall
11+
ret
12+
NtProtectVirtualMemory ENDP
13+
14+
KiSystemCall PROC
15+
IFDEF RAX
16+
mov r10,rcx
17+
syscall
18+
ret
19+
ELSE
20+
db 234
21+
dd exit
22+
dw 51
23+
exit:
24+
inc ecx
25+
jmp dword ptr [edi+248]
26+
ENDIF
27+
KiSystemCall ENDP
28+
29+
END

RS_ASIO/Patcher.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22
#include "dllmain.h"
33
#include "crc32.h"
44

5+
EXTERN_C ULONG NtProtectVirtualMemory(
6+
IN HANDLE ProcessHandle,
7+
IN OUT PVOID* BaseAddress,
8+
IN OUT PSIZE_T RegionSize,
9+
IN ULONG NewProtect,
10+
OUT PULONG OldProtect
11+
);
12+
13+
bool VirtualProtectSyscall(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
14+
{
15+
return NtProtectVirtualMemory(GetCurrentProcess(), &lpAddress, &dwSize, flNewProtect, lpflOldProtect) == 0;
16+
}
17+
518
DWORD GetImageCrc32()
619
{
720
char exePath[MAX_PATH]{};
@@ -20,6 +33,7 @@ DWORD GetImageCrc32()
2033

2134
void PatchOriginalCode_d1b38fcb();
2235
void PatchOriginalCode_21a8959a();
36+
void PatchOriginalCode_6ea6d1ba();
2337

2438
std::vector<void*> FindBytesOffsets(const BYTE* bytes, size_t numBytes)
2539
{
@@ -57,7 +71,7 @@ std::vector<void*> FindBytesOffsets(const BYTE* bytes, size_t numBytes)
5771
return result;
5872
}
5973

60-
void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void* TargetFn)
74+
void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void* TargetFn, size_t numNopsFollowing)
6175
{
6276
rslog::info_ts() << __FUNCTION__ " - num locations: " << offsets.size() << std::endl;
6377

@@ -70,7 +84,7 @@ void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void*
7084
BYTE* bytes = (BYTE*)offset;
7185

7286
DWORD oldProtectFlags = 0;
73-
if (!VirtualProtect(offset, 6, PAGE_WRITECOPY, &oldProtectFlags))
87+
if (!VirtualProtectSyscall(offset, 6, PAGE_WRITECOPY, &oldProtectFlags))
7488
{
7589
rslog::error_ts() << "Failed to change memory protection" << std::endl;
7690
}
@@ -79,10 +93,13 @@ void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void*
7993
bytes[0] = 0xe8;
8094
void** callAddress = (void**)(bytes + 1);
8195
*callAddress = (void*)targetRelAddress;
82-
bytes[5] = 0x90;
96+
for (size_t i = 0; i < numNopsFollowing; ++i)
97+
{
98+
bytes[5+i] = 0x90;
99+
}
83100

84-
FlushInstructionCache(GetCurrentProcess(), offset, 6);
85-
if (!VirtualProtect(offset, 6, oldProtectFlags, &oldProtectFlags))
101+
FlushInstructionCache(GetCurrentProcess(), offset, 5+numNopsFollowing);
102+
if (!VirtualProtectSyscall(offset, 5 + numNopsFollowing, oldProtectFlags, &oldProtectFlags))
86103
{
87104
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
88105
}
@@ -106,7 +123,7 @@ void Patch_CallRelativeAddress(const std::vector<void*>& offsets, void* TargetFn
106123
bytes += 5 + relOffset;
107124

108125
DWORD oldProtectFlags = 0;
109-
if (!VirtualProtect(bytes, 6, PAGE_WRITECOPY, &oldProtectFlags))
126+
if (!VirtualProtectSyscall(bytes, 6, PAGE_WRITECOPY, &oldProtectFlags))
110127
{
111128
rslog::error_ts() << "Failed to change memory protection" << std::endl;
112129
}
@@ -119,7 +136,7 @@ void Patch_CallRelativeAddress(const std::vector<void*>& offsets, void* TargetFn
119136
// ret
120137
bytes[5] = 0xc3;
121138

122-
if (!VirtualProtect(bytes, 6, oldProtectFlags, &oldProtectFlags))
139+
if (!VirtualProtectSyscall(bytes, 6, oldProtectFlags, &oldProtectFlags))
123140
{
124141
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
125142
}
@@ -130,7 +147,7 @@ void Patch_CallRelativeAddress(const std::vector<void*>& offsets, void* TargetFn
130147
void Patch_ReplaceWithNops(void* offset, size_t numBytes)
131148
{
132149
DWORD oldProtectFlags = 0;
133-
if (!VirtualProtect(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
150+
if (!VirtualProtectSyscall(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
134151
{
135152
rslog::error_ts() << "Failed to change memory protection" << std::endl;
136153
}
@@ -143,7 +160,7 @@ void Patch_ReplaceWithNops(void* offset, size_t numBytes)
143160
}
144161

145162
FlushInstructionCache(GetCurrentProcess(), offset, numBytes);
146-
if (!VirtualProtect(offset, numBytes, oldProtectFlags, &oldProtectFlags))
163+
if (!VirtualProtectSyscall(offset, numBytes, oldProtectFlags, &oldProtectFlags))
147164
{
148165
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
149166
}
@@ -153,7 +170,7 @@ void Patch_ReplaceWithNops(void* offset, size_t numBytes)
153170
void Patch_ReplaceWithBytes(void* offset, size_t numBytes, const BYTE* replaceBytes)
154171
{
155172
DWORD oldProtectFlags = 0;
156-
if (!VirtualProtect(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
173+
if (!VirtualProtectSyscall(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
157174
{
158175
rslog::error_ts() << "Failed to change memory protection" << std::endl;
159176
}
@@ -166,7 +183,7 @@ void Patch_ReplaceWithBytes(void* offset, size_t numBytes, const BYTE* replaceBy
166183
}
167184

168185
FlushInstructionCache(GetCurrentProcess(), offset, numBytes);
169-
if (!VirtualProtect(offset, numBytes, oldProtectFlags, &oldProtectFlags))
186+
if (!VirtualProtectSyscall(offset, numBytes, oldProtectFlags, &oldProtectFlags))
170187
{
171188
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
172189
}
@@ -192,6 +209,9 @@ void PatchOriginalCode()
192209
case 0x21a8959a:
193210
PatchOriginalCode_21a8959a();
194211
break;
212+
case 0x6ea6d1ba:
213+
PatchOriginalCode_6ea6d1ba();
214+
break;
195215
default:
196216
rslog::error_ts() << "Unknown game version" << std::endl;
197217
break;

RS_ASIO/Patcher.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
void PatchOriginalCode();
44

55
std::vector<void*> FindBytesOffsets(const BYTE* bytes, size_t numBytes);
6-
void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void* TargetFn);
6+
void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void* TargetFn, size_t numNopsFollowing=0);
77
void Patch_CallRelativeAddress(const std::vector<void*>& offsets, void* TargetFn);
88
void Patch_ReplaceWithNops(void* offset, size_t numBytes);
99
void Patch_ReplaceWithBytes(void* offset, size_t numBytes, const BYTE* replaceBytes);

RS_ASIO/Patcher_21a8959a.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void PatchOriginalCode_21a8959a()
6868
{
6969
// patch CoCreateInstance calls
7070
rslog::info_ts() << "Patching CoCreateInstance" << std::endl;
71-
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstance, &Patched_CoCreateInstance);
71+
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstance, &Patched_CoCreateInstance, 1);
7272

7373
// patch PortAudio MarshalStreamComPointers
7474
rslog::info_ts() << "Patching PortAudio MarshalStreamComPointers" << std::endl;

RS_ASIO/Patcher_6ea6d1ba.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include "stdafx.h"
2+
#include "dllmain.h"
3+
#include "Patcher.h"
4+
#include "crc32.h"
5+
6+
// this file contains the patch code for the game version released ON 2024-12-19 (Rocksmith 2014 Remastered Learn & Play)
7+
8+
static const BYTE originalBytes_call_CoCreateInstance[]{
9+
0x56, // push esi
10+
0xe8, 0x0e, 0x16, 0x94, 0x00, // call relative
11+
0x85, 0xc0, // test eax, eax
12+
0x0f, 0x88, 0xaa, 0x0c, 0x00, 0x00 // js ...
13+
};
14+
15+
static const BYTE originalBytes_call_PortAudio_MarshalStreamComPointers[]{
16+
0xe8, 0xec, 0xe4, 0xff, 0xff, // call
17+
0x83, 0xc4, 0x04, // add esp, 4
18+
0x85, 0xc0 // test eax, eax
19+
};
20+
21+
static const BYTE originalBytes_call_UnmarshalStreamComPointers[]{
22+
0xe8, 0xd6, 0xfd, 0xff, 0xff, // call
23+
0x56, // push esi
24+
0xe8, 0xb0, 0xfe, 0xff, 0xff // call (to another uninteresting function)
25+
};
26+
27+
static const BYTE originalBytes_TwoRealToneCablesMessageBoxStarting[]{
28+
0x74, 0x6b, // jz ...
29+
0xba, 0x5c, 0x16, 0x8b, 0x01 // mov edx, offset "TooManyGuitarInputs"
30+
};
31+
32+
static const BYTE originalBytes_TwoRealToneCablesMessageBoxMainMenu[]{
33+
0x0f, 0x84, 0x95, 0x00, 0x00, 0x00, // jz ...
34+
0xba, 0x70, 0x16, 0x8b, 0x01, // mov edx, offset "$[34872]Warning! Two Rocksmith Real Ton..."
35+
0x8d, 0x75, 0xb0 // lea esi, [ebp+...]
36+
};
37+
38+
template<typename T>
39+
void vector_append(std::vector<T>& inOut, const std::vector<T>& source)
40+
{
41+
for (auto& it : source)
42+
{
43+
inOut.push_back(it);
44+
}
45+
}
46+
47+
void PatchOriginalCode_6ea6d1ba()
48+
{
49+
std::vector<void*> offsets_CoCreateInstanceAbs = FindBytesOffsets(originalBytes_call_CoCreateInstance, sizeof(originalBytes_call_CoCreateInstance));
50+
51+
std::vector<void*> offsets_PaMarshalPointers = FindBytesOffsets(originalBytes_call_PortAudio_MarshalStreamComPointers, sizeof(originalBytes_call_PortAudio_MarshalStreamComPointers));
52+
std::vector<void*> offsets_PaUnmarshalPointers = FindBytesOffsets(originalBytes_call_UnmarshalStreamComPointers, sizeof(originalBytes_call_UnmarshalStreamComPointers));
53+
54+
std::vector<void*> offsets_TwoRealToneCablesMessageBoxStarting = FindBytesOffsets(originalBytes_TwoRealToneCablesMessageBoxStarting, sizeof(originalBytes_TwoRealToneCablesMessageBoxStarting));
55+
std::vector<void*> offsets_TwoRealToneCablesMessageBoxMainMenu = FindBytesOffsets(originalBytes_TwoRealToneCablesMessageBoxMainMenu, sizeof(originalBytes_TwoRealToneCablesMessageBoxMainMenu));
56+
57+
if (offsets_CoCreateInstanceAbs.size() == 0 && offsets_PaMarshalPointers.size() == 0 && offsets_PaUnmarshalPointers.size() == 0)
58+
{
59+
rslog::error_ts() << "No valid locations for patching were found. Make sure you're trying this on the right game version." << std::endl;
60+
}
61+
else
62+
{
63+
// patch CoCreateInstance calls
64+
rslog::info_ts() << "Patching CoCreateInstance" << std::endl;
65+
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstanceAbs, &Patched_CoCreateInstance, 1);
66+
67+
// patch PortAudio MarshalStreamComPointers
68+
rslog::info_ts() << "Patching PortAudio MarshalStreamComPointers" << std::endl;
69+
Patch_CallRelativeAddress(offsets_PaMarshalPointers, &Patched_PortAudio_MarshalStreamComPointers);
70+
71+
// patch PortAudio UnmarshalStreamComPointers
72+
rslog::info_ts() << "Patching PortAudio UnmarshalStreamComPointers" << std::endl;
73+
Patch_CallRelativeAddress(offsets_PaUnmarshalPointers, &Patched_PortAudio_UnmarshalStreamComPointers);
74+
75+
// patch two guitar cables connected message in single-player
76+
rslog::info_ts() << "Patching Two Guitar Tones Connected Message Box (starting menu) (num locations: " << offsets_TwoRealToneCablesMessageBoxStarting.size() << ")" << std::endl;
77+
for (void* offset : offsets_TwoRealToneCablesMessageBoxStarting)
78+
{
79+
const BYTE replaceBytes[]
80+
{
81+
0xeb, // jmp rel8
82+
};
83+
rslog::info_ts() << "Patching bytes at " << offset << std::endl;
84+
Patch_ReplaceWithBytes(offset, sizeof(replaceBytes), replaceBytes);
85+
}
86+
87+
rslog::info_ts() << "Patching Two Guitar Tones Connected Message Box (main menu) (num locations: " << offsets_TwoRealToneCablesMessageBoxMainMenu.size() << ")" << std::endl;
88+
for (void* offset : offsets_TwoRealToneCablesMessageBoxMainMenu)
89+
{
90+
const BYTE replaceBytes[]
91+
{
92+
0x90, // original instruction at this point is 6 byte wide, we only need 5 bytes, so put a nop here
93+
0xe9, // jmp rel32
94+
};
95+
rslog::info_ts() << "Patching bytes at " << offset << std::endl;
96+
Patch_ReplaceWithBytes(offset, sizeof(replaceBytes), replaceBytes);
97+
}
98+
}
99+
}

RS_ASIO/Patcher_d1b38fcb.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void PatchOriginalCode_d1b38fcb()
102102
{
103103
// patch CoCreateInstance calls
104104
rslog::info_ts() << "Patching CoCreateInstance" << std::endl;
105-
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstanceAbs, &Patched_CoCreateInstance);
105+
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstanceAbs, &Patched_CoCreateInstance, 1);
106106
//Patch_CallRelativeAddress<(void*)&Patched_CoCreateInstance>(offsets_CoCreateInstanceRel);
107107

108108
// patch PortAudio MarshalStreamComPointers

RS_ASIO/RS_ASIO.args.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"FileVersion": 2,
3+
"Id": "4339185f-e3ea-4fe0-bbd7-67d4fe3fbf3e",
4+
"Items": [
5+
{
6+
"Id": "a2d778b6-ffaf-451e-84f5-66f351588f71",
7+
"Command": ""
8+
}
9+
]
10+
}

RS_ASIO/RS_ASIO.vcxproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
</PropertyGroup>
5656
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
5757
<ImportGroup Label="ExtensionSettings">
58+
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
5859
</ImportGroup>
5960
<ImportGroup Label="Shared">
6061
</ImportGroup>
@@ -137,6 +138,7 @@
137138
<OptimizeReferences>true</OptimizeReferences>
138139
<GenerateDebugInformation>false</GenerateDebugInformation>
139140
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
141+
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
140142
</Link>
141143
</ItemDefinitionGroup>
142144
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -210,6 +212,7 @@
210212
<ClCompile Include="dllmain.cpp" />
211213
<ClCompile Include="Log.cpp" />
212214
<ClCompile Include="Patcher.cpp" />
215+
<ClCompile Include="Patcher_6ea6d1ba.cpp" />
213216
<ClCompile Include="Patcher_d1b38fcb.cpp" />
214217
<ClCompile Include="Patcher_21a8959a.cpp" />
215218
<ClCompile Include="RSAsioAudioCaptureClient.cpp" />
@@ -236,7 +239,11 @@
236239
<ItemGroup>
237240
<None Include="exports.def" />
238241
</ItemGroup>
242+
<ItemGroup>
243+
<MASM Include="NtProtectVirtualMemory.asm" />
244+
</ItemGroup>
239245
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
240246
<ImportGroup Label="ExtensionTargets">
247+
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
241248
</ImportGroup>
242249
</Project>

RS_ASIO/RS_ASIO.vcxproj.filters

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,18 @@
215215
<ClCompile Include="RSAsioAudioClientServiceBase.cpp">
216216
<Filter>Source Files</Filter>
217217
</ClCompile>
218+
<ClCompile Include="Patcher_6ea6d1ba.cpp">
219+
<Filter>Source Files</Filter>
220+
</ClCompile>
218221
</ItemGroup>
219222
<ItemGroup>
220223
<None Include="exports.def">
221224
<Filter>Source Files</Filter>
222225
</None>
223226
</ItemGroup>
227+
<ItemGroup>
228+
<MASM Include="NtProtectVirtualMemory.asm">
229+
<Filter>Source Files</Filter>
230+
</MASM>
231+
</ItemGroup>
224232
</Project>

0 commit comments

Comments
 (0)