mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 01:06:50 +02:00
Patch checksum AP in Last Window: The Secret of Cape West (#104)
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
#include "patches/arm9/OSResetSystemPatch.h"
|
#include "patches/arm9/OSResetSystemPatch.h"
|
||||||
#include "patches/arm9/PokemonDownloaderArm9Patch.h"
|
#include "patches/arm9/PokemonDownloaderArm9Patch.h"
|
||||||
#include "patches/arm9/DSProtectArm9Patch.h"
|
#include "patches/arm9/DSProtectArm9Patch.h"
|
||||||
|
#include "patches/arm9/LastWindowCrcPatch.h"
|
||||||
#include "patches/arm9/NandSave/FaceTrainingNandSavePatch.h"
|
#include "patches/arm9/NandSave/FaceTrainingNandSavePatch.h"
|
||||||
#include "patches/arm9/NandSave/JamWithTheBandNandSavePatch.h"
|
#include "patches/arm9/NandSave/JamWithTheBandNandSavePatch.h"
|
||||||
#include "patches/arm9/NandSave/NintendoDSGuideNandSavePatch.h"
|
#include "patches/arm9/NandSave/NintendoDSGuideNandSavePatch.h"
|
||||||
@@ -404,6 +405,12 @@ void Arm9Patcher::AddGameSpecificPatches(
|
|||||||
patchCollection.AddPatch(new NintendoDSGuideNandSavePatch());
|
patchCollection.AddPatch(new NintendoDSGuideNandSavePatch());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Last Window: The Secret of Cape West
|
||||||
|
case GAMECODE("YLUP"):
|
||||||
|
{
|
||||||
|
patchCollection.AddPatch(new LastWindowCrcPatch());
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Rabbids Go Home
|
// Rabbids Go Home
|
||||||
case GAMECODE("VRGE"):
|
case GAMECODE("VRGE"):
|
||||||
case GAMECODE("VRGV"):
|
case GAMECODE("VRGV"):
|
||||||
|
|||||||
18
arm9/source/patches/arm9/LastWindowCrcPatch.cpp
Normal file
18
arm9/source/patches/arm9/LastWindowCrcPatch.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "patches/PatchContext.h"
|
||||||
|
#include "LastWindowCrcPatchCode.h"
|
||||||
|
#include "LastWindowCrcPatch.h"
|
||||||
|
|
||||||
|
bool LastWindowCrcPatch::FindPatchTarget(PatchContext& patchContext)
|
||||||
|
{
|
||||||
|
_getCrc16 = (u32*)0x020304B4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LastWindowCrcPatch::ApplyPatch(PatchContext& patchContext)
|
||||||
|
{
|
||||||
|
auto patchCode = patchContext.GetPatchCodeCollection().AddUniquePatchCode<LastWindowCrcPatchCode>(patchContext.GetPatchHeap());
|
||||||
|
u32 patchAddr = (u32)patchCode->GetLastWindowCrcFunction();
|
||||||
|
*_getCrc16 = MakeBlxCall(patchAddr);
|
||||||
|
}
|
||||||
|
|
||||||
40
arm9/source/patches/arm9/LastWindowCrcPatch.h
Normal file
40
arm9/source/patches/arm9/LastWindowCrcPatch.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Patch.h"
|
||||||
|
|
||||||
|
/// @brief Arm9 patch for intercepting calls to SVC_GetCRC16 in The Last Window: The Secret of Cape West
|
||||||
|
/// @details
|
||||||
|
/// This game has DS Protect 1.27, which is patched by the regular DS Protect patches, but also has
|
||||||
|
/// an extra layer of CRC checks that must match or the game will fail to boot.
|
||||||
|
///
|
||||||
|
/// It first runs DS Protect NotA1 at startup, and then does a CRC of most of DS Protect. This can
|
||||||
|
/// tell which DS Protect functions were run, because at decrypt-run-encrypt, the key gets changed.
|
||||||
|
/// So the CRC is sensitive not only to code modifications, but also to which encrypted functions
|
||||||
|
/// were run, and how many times they were run.
|
||||||
|
///
|
||||||
|
/// The current DS Protect patch modifies NotA1, causes one of its subfunction to run twice, and
|
||||||
|
/// the other subfunction to not be run, which obviously breaks the CRC.
|
||||||
|
///
|
||||||
|
/// Another region is also CRCed, from 0202DB34 to 02030334. What resides here is unknown, it does not
|
||||||
|
/// contain any commonly modified functions such as AP or card reading.
|
||||||
|
///
|
||||||
|
/// To make things more annoying, the memory location of the correct CRC is randomized, and the code
|
||||||
|
/// that checks the CRC resides in a compressed overlay which is loaded into ITCM. This same function
|
||||||
|
/// also receives several dummy checks that are expected to fail, and so cannot be patched to always
|
||||||
|
/// report the CRC matches.
|
||||||
|
///
|
||||||
|
/// Instead, the function call that calculates the CRC is shimmed and if its arguments match
|
||||||
|
/// a problematic CRC calculation, the expected answer is returned instead.
|
||||||
|
class LastWindowCrcPatch : public Patch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool FindPatchTarget(PatchContext& patchContext) override;
|
||||||
|
void ApplyPatch(PatchContext& patchContext) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
u32* _getCrc16 = nullptr;
|
||||||
|
|
||||||
|
u32 MakeBlxCall(u32 patchAddr) const
|
||||||
|
{
|
||||||
|
return 0xFA000000 | (((patchAddr - (u32)_getCrc16 - 8) >> 2) & 0xFFFFFF);
|
||||||
|
}
|
||||||
|
};
|
||||||
20
arm9/source/patches/arm9/LastWindowCrcPatchCode.h
Normal file
20
arm9/source/patches/arm9/LastWindowCrcPatchCode.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../PatchCode.h"
|
||||||
|
#include "sections.h"
|
||||||
|
|
||||||
|
DEFINE_SECTION_SYMBOLS(patch_lastwindowcrc);
|
||||||
|
|
||||||
|
extern "C" void patch_lastwindowcrc_entry(void);
|
||||||
|
|
||||||
|
class LastWindowCrcPatchCode : public PatchCode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LastWindowCrcPatchCode(PatchHeap& patchHeap)
|
||||||
|
: PatchCode(SECTION_START(patch_lastwindowcrc), SECTION_SIZE(patch_lastwindowcrc), patchHeap)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
const void* GetLastWindowCrcFunction() const
|
||||||
|
{
|
||||||
|
return GetAddressAtTarget((void*)patch_lastwindowcrc_entry);
|
||||||
|
}
|
||||||
|
};
|
||||||
30
arm9/source/patches/arm9/LastWindowCrcPatchCode.s
Normal file
30
arm9/source/patches/arm9/LastWindowCrcPatchCode.s
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
.cpu arm946e-s
|
||||||
|
.section "patch_lastwindowcrc", "ax"
|
||||||
|
.syntax unified
|
||||||
|
|
||||||
|
.thumb
|
||||||
|
.global patch_lastwindowcrc_entry
|
||||||
|
.type patch_lastwindowcrc_entry, %function
|
||||||
|
patch_lastwindowcrc_entry:
|
||||||
|
// r0=crc_start, r1=datap, r2=size
|
||||||
|
ldr r3, =0x0207D4F4 // CRC of DS Protect region
|
||||||
|
cmp r1, r3
|
||||||
|
beq crc_dsprotect
|
||||||
|
|
||||||
|
ldr r3, =0x0202DB34 // CRC of other code region (unknown)
|
||||||
|
cmp r1, r3
|
||||||
|
beq crc_unk
|
||||||
|
|
||||||
|
swi #0xE // Normal CRC if address does not match (never hit?)
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
crc_dsprotect:
|
||||||
|
ldr r0, =0x67D7
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
crc_unk:
|
||||||
|
ldr r0, =0x0D1E
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
.pool
|
||||||
|
.end
|
||||||
Reference in New Issue
Block a user