Skip to content

Commit

Permalink
Add support to game image with crc32 6ea6d1ba
Browse files Browse the repository at this point in the history
- Use direct syscalls to change memory protection options
  • Loading branch information
mdias committed Dec 24, 2024
1 parent 97e6e0a commit 3cd33df
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 14 deletions.
29 changes: 29 additions & 0 deletions RS_ASIO/NtProtectVirtualMemory.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
IFNDEF RAX
.MODEL FLAT, C
ENDIF
.CODE
NtProtectVirtualMemory PROC
mov eax, 50h
call KiSystemCall
ret
NtProtectVirtualMemory ENDP
KiSystemCall PROC
IFDEF RAX
mov r10,rcx
syscall
ret
ELSE
db 234
dd exit
dw 51
exit:
inc ecx
jmp dword ptr [edi+248]
ENDIF
KiSystemCall ENDP
END
42 changes: 31 additions & 11 deletions RS_ASIO/Patcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
#include "dllmain.h"
#include "crc32.h"

EXTERN_C ULONG NtProtectVirtualMemory(
IN HANDLE ProcessHandle,
IN OUT PVOID* BaseAddress,
IN OUT PSIZE_T RegionSize,
IN ULONG NewProtect,
OUT PULONG OldProtect
);

bool VirtualProtectSyscall(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
return NtProtectVirtualMemory(GetCurrentProcess(), &lpAddress, &dwSize, flNewProtect, lpflOldProtect) == 0;
}

DWORD GetImageCrc32()
{
char exePath[MAX_PATH]{};
Expand All @@ -20,6 +33,7 @@ DWORD GetImageCrc32()

void PatchOriginalCode_d1b38fcb();
void PatchOriginalCode_21a8959a();
void PatchOriginalCode_6ea6d1ba();

std::vector<void*> FindBytesOffsets(const BYTE* bytes, size_t numBytes)
{
Expand Down Expand Up @@ -57,7 +71,7 @@ std::vector<void*> FindBytesOffsets(const BYTE* bytes, size_t numBytes)
return result;
}

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

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

DWORD oldProtectFlags = 0;
if (!VirtualProtect(offset, 6, PAGE_WRITECOPY, &oldProtectFlags))
if (!VirtualProtectSyscall(offset, 6, PAGE_WRITECOPY, &oldProtectFlags))
{
rslog::error_ts() << "Failed to change memory protection" << std::endl;
}
Expand All @@ -79,10 +93,13 @@ void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void*
bytes[0] = 0xe8;
void** callAddress = (void**)(bytes + 1);
*callAddress = (void*)targetRelAddress;
bytes[5] = 0x90;
for (size_t i = 0; i < numNopsFollowing; ++i)
{
bytes[5+i] = 0x90;
}

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

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

if (!VirtualProtect(bytes, 6, oldProtectFlags, &oldProtectFlags))
if (!VirtualProtectSyscall(bytes, 6, oldProtectFlags, &oldProtectFlags))
{
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
}
Expand All @@ -130,7 +147,7 @@ void Patch_CallRelativeAddress(const std::vector<void*>& offsets, void* TargetFn
void Patch_ReplaceWithNops(void* offset, size_t numBytes)
{
DWORD oldProtectFlags = 0;
if (!VirtualProtect(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
if (!VirtualProtectSyscall(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
{
rslog::error_ts() << "Failed to change memory protection" << std::endl;
}
Expand All @@ -143,7 +160,7 @@ void Patch_ReplaceWithNops(void* offset, size_t numBytes)
}

FlushInstructionCache(GetCurrentProcess(), offset, numBytes);
if (!VirtualProtect(offset, numBytes, oldProtectFlags, &oldProtectFlags))
if (!VirtualProtectSyscall(offset, numBytes, oldProtectFlags, &oldProtectFlags))
{
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
}
Expand All @@ -153,7 +170,7 @@ void Patch_ReplaceWithNops(void* offset, size_t numBytes)
void Patch_ReplaceWithBytes(void* offset, size_t numBytes, const BYTE* replaceBytes)
{
DWORD oldProtectFlags = 0;
if (!VirtualProtect(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
if (!VirtualProtectSyscall(offset, numBytes, PAGE_WRITECOPY, &oldProtectFlags))
{
rslog::error_ts() << "Failed to change memory protection" << std::endl;
}
Expand All @@ -166,7 +183,7 @@ void Patch_ReplaceWithBytes(void* offset, size_t numBytes, const BYTE* replaceBy
}

FlushInstructionCache(GetCurrentProcess(), offset, numBytes);
if (!VirtualProtect(offset, numBytes, oldProtectFlags, &oldProtectFlags))
if (!VirtualProtectSyscall(offset, numBytes, oldProtectFlags, &oldProtectFlags))
{
rslog::error_ts() << "Failed to restore memory protection" << std::endl;
}
Expand All @@ -192,6 +209,9 @@ void PatchOriginalCode()
case 0x21a8959a:
PatchOriginalCode_21a8959a();
break;
case 0x6ea6d1ba:
PatchOriginalCode_6ea6d1ba();
break;
default:
rslog::error_ts() << "Unknown game version" << std::endl;
break;
Expand Down
2 changes: 1 addition & 1 deletion RS_ASIO/Patcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
void PatchOriginalCode();

std::vector<void*> FindBytesOffsets(const BYTE* bytes, size_t numBytes);
void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void* TargetFn);
void Patch_CallAbsoluteIndirectAddress(const std::vector<void*>& offsets, void* TargetFn, size_t numNopsFollowing=0);
void Patch_CallRelativeAddress(const std::vector<void*>& offsets, void* TargetFn);
void Patch_ReplaceWithNops(void* offset, size_t numBytes);
void Patch_ReplaceWithBytes(void* offset, size_t numBytes, const BYTE* replaceBytes);
2 changes: 1 addition & 1 deletion RS_ASIO/Patcher_21a8959a.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void PatchOriginalCode_21a8959a()
{
// patch CoCreateInstance calls
rslog::info_ts() << "Patching CoCreateInstance" << std::endl;
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstance, &Patched_CoCreateInstance);
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstance, &Patched_CoCreateInstance, 1);

// patch PortAudio MarshalStreamComPointers
rslog::info_ts() << "Patching PortAudio MarshalStreamComPointers" << std::endl;
Expand Down
99 changes: 99 additions & 0 deletions RS_ASIO/Patcher_6ea6d1ba.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include "stdafx.h"
#include "dllmain.h"
#include "Patcher.h"
#include "crc32.h"

// this file contains the patch code for the game version released ON 2024-12-19 (Rocksmith 2014 Remastered Learn & Play)

static const BYTE originalBytes_call_CoCreateInstance[]{
0x56, // push esi
0xe8, 0x0e, 0x16, 0x94, 0x00, // call relative
0x85, 0xc0, // test eax, eax
0x0f, 0x88, 0xaa, 0x0c, 0x00, 0x00 // js ...
};

static const BYTE originalBytes_call_PortAudio_MarshalStreamComPointers[]{
0xe8, 0xec, 0xe4, 0xff, 0xff, // call
0x83, 0xc4, 0x04, // add esp, 4
0x85, 0xc0 // test eax, eax
};

static const BYTE originalBytes_call_UnmarshalStreamComPointers[]{
0xe8, 0xd6, 0xfd, 0xff, 0xff, // call
0x56, // push esi
0xe8, 0xb0, 0xfe, 0xff, 0xff // call (to another uninteresting function)
};

static const BYTE originalBytes_TwoRealToneCablesMessageBoxStarting[]{
0x74, 0x6b, // jz ...
0xba, 0x5c, 0x16, 0x8b, 0x01 // mov edx, offset "TooManyGuitarInputs"
};

static const BYTE originalBytes_TwoRealToneCablesMessageBoxMainMenu[]{
0x0f, 0x84, 0x95, 0x00, 0x00, 0x00, // jz ...
0xba, 0x70, 0x16, 0x8b, 0x01, // mov edx, offset "$[34872]Warning! Two Rocksmith Real Ton..."
0x8d, 0x75, 0xb0 // lea esi, [ebp+...]
};

template<typename T>
void vector_append(std::vector<T>& inOut, const std::vector<T>& source)
{
for (auto& it : source)
{
inOut.push_back(it);
}
}

void PatchOriginalCode_6ea6d1ba()
{
std::vector<void*> offsets_CoCreateInstanceAbs = FindBytesOffsets(originalBytes_call_CoCreateInstance, sizeof(originalBytes_call_CoCreateInstance));

std::vector<void*> offsets_PaMarshalPointers = FindBytesOffsets(originalBytes_call_PortAudio_MarshalStreamComPointers, sizeof(originalBytes_call_PortAudio_MarshalStreamComPointers));
std::vector<void*> offsets_PaUnmarshalPointers = FindBytesOffsets(originalBytes_call_UnmarshalStreamComPointers, sizeof(originalBytes_call_UnmarshalStreamComPointers));

std::vector<void*> offsets_TwoRealToneCablesMessageBoxStarting = FindBytesOffsets(originalBytes_TwoRealToneCablesMessageBoxStarting, sizeof(originalBytes_TwoRealToneCablesMessageBoxStarting));
std::vector<void*> offsets_TwoRealToneCablesMessageBoxMainMenu = FindBytesOffsets(originalBytes_TwoRealToneCablesMessageBoxMainMenu, sizeof(originalBytes_TwoRealToneCablesMessageBoxMainMenu));

if (offsets_CoCreateInstanceAbs.size() == 0 && offsets_PaMarshalPointers.size() == 0 && offsets_PaUnmarshalPointers.size() == 0)
{
rslog::error_ts() << "No valid locations for patching were found. Make sure you're trying this on the right game version." << std::endl;
}
else
{
// patch CoCreateInstance calls
rslog::info_ts() << "Patching CoCreateInstance" << std::endl;
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstanceAbs, &Patched_CoCreateInstance, 1);

// patch PortAudio MarshalStreamComPointers
rslog::info_ts() << "Patching PortAudio MarshalStreamComPointers" << std::endl;
Patch_CallRelativeAddress(offsets_PaMarshalPointers, &Patched_PortAudio_MarshalStreamComPointers);

// patch PortAudio UnmarshalStreamComPointers
rslog::info_ts() << "Patching PortAudio UnmarshalStreamComPointers" << std::endl;
Patch_CallRelativeAddress(offsets_PaUnmarshalPointers, &Patched_PortAudio_UnmarshalStreamComPointers);

// patch two guitar cables connected message in single-player
rslog::info_ts() << "Patching Two Guitar Tones Connected Message Box (starting menu) (num locations: " << offsets_TwoRealToneCablesMessageBoxStarting.size() << ")" << std::endl;
for (void* offset : offsets_TwoRealToneCablesMessageBoxStarting)
{
const BYTE replaceBytes[]
{
0xeb, // jmp rel8
};
rslog::info_ts() << "Patching bytes at " << offset << std::endl;
Patch_ReplaceWithBytes(offset, sizeof(replaceBytes), replaceBytes);
}

rslog::info_ts() << "Patching Two Guitar Tones Connected Message Box (main menu) (num locations: " << offsets_TwoRealToneCablesMessageBoxMainMenu.size() << ")" << std::endl;
for (void* offset : offsets_TwoRealToneCablesMessageBoxMainMenu)
{
const BYTE replaceBytes[]
{
0x90, // original instruction at this point is 6 byte wide, we only need 5 bytes, so put a nop here
0xe9, // jmp rel32
};
rslog::info_ts() << "Patching bytes at " << offset << std::endl;
Patch_ReplaceWithBytes(offset, sizeof(replaceBytes), replaceBytes);
}
}
}
2 changes: 1 addition & 1 deletion RS_ASIO/Patcher_d1b38fcb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void PatchOriginalCode_d1b38fcb()
{
// patch CoCreateInstance calls
rslog::info_ts() << "Patching CoCreateInstance" << std::endl;
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstanceAbs, &Patched_CoCreateInstance);
Patch_CallAbsoluteIndirectAddress(offsets_CoCreateInstanceAbs, &Patched_CoCreateInstance, 1);
//Patch_CallRelativeAddress<(void*)&Patched_CoCreateInstance>(offsets_CoCreateInstanceRel);

// patch PortAudio MarshalStreamComPointers
Expand Down
10 changes: 10 additions & 0 deletions RS_ASIO/RS_ASIO.args.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"FileVersion": 2,
"Id": "4339185f-e3ea-4fe0-bbd7-67d4fe3fbf3e",
"Items": [
{
"Id": "a2d778b6-ffaf-451e-84f5-66f351588f71",
"Command": ""
}
]
}
7 changes: 7 additions & 0 deletions RS_ASIO/RS_ASIO.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
Expand Down Expand Up @@ -137,6 +138,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
Expand Down Expand Up @@ -210,6 +212,7 @@
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Patcher.cpp" />
<ClCompile Include="Patcher_6ea6d1ba.cpp" />
<ClCompile Include="Patcher_d1b38fcb.cpp" />
<ClCompile Include="Patcher_21a8959a.cpp" />
<ClCompile Include="RSAsioAudioCaptureClient.cpp" />
Expand All @@ -236,7 +239,11 @@
<ItemGroup>
<None Include="exports.def" />
</ItemGroup>
<ItemGroup>
<MASM Include="NtProtectVirtualMemory.asm" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
8 changes: 8 additions & 0 deletions RS_ASIO/RS_ASIO.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,18 @@
<ClCompile Include="RSAsioAudioClientServiceBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Patcher_6ea6d1ba.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="exports.def">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<MASM Include="NtProtectVirtualMemory.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>

0 comments on commit 3cd33df

Please sign in to comment.