The following analysis attempts to override the earnings in the "Cash" application in Saints Row 2022 in order to create a money cheat. The beauty of leveraging the "Cash Transfer" in order to create a money cheat is that the game continuously increases the earnings such that no direct value injection is necessary.
With the game open, the "Cash" mobile application is opened using the phone key, the game is set to break mode using the "Advanced" Cheat Engine button and the currently displayed earnings are searched. The game can be taken out of break mode using the "Advanced" feature of Cheat Engine and the search repeated until a single address is found. Using the access monitor, access to the found address is watched for changes until the following changes are found:
89 7FF787826D10 - 8B 05 42943802 - mov eax,[7FF789BB0158] 1 7FF7879CD8D2 - 8B 3D 80281E02 - mov edi,[7FF789BB0158] 1 7FF7879CD91B - 89 3D 37281E02 - mov [7FF789BB0158],edi
as it turns out, every time the earnings are increased, the second and last instructions are executed while the first instruction seems to be executed even when the earnings are not increased.
Disassembling the code, the second instruction is explained by the comment:
SaintsRow.exe+B1D8D2 - 8B 3D 80281E02 - mov edi,[SaintsRow.exe+2D00158] { (1132510) }
It seems that the decimal value 1132510
corresponds to the current earnings in the "Cash" application and the value changes as the earnings accumulate such that the relative address SaintsRow.exe+2D00158
must be a generator of sorts that increments the earnings.
In order to increase the earnings instantly, the previous instruction is modified to, say:
7FF786EA0000 - BF 40420F00 - mov edi,000F4240 { 1000000 }
That is, load the register edi
with the value 000F4240
(1000000
in decimal). After the change, the "Cash" application displays roughly $1 million and does not increase because the value is now fixed instead of being generated by the routine at SaintsRow.exe+2D00158
.
{ Game : Saints Row -- DX11 Version: Date : 2023-03-02 Author : Wizardry and Steamworks (wizardry.steamworks@outlook.com) This script sets the cash transfer value to 1mil ready to be transferred. } define(address,"SaintsRow.exe"+B1D8D2) define(bytes,8B 3D 80 28 1E 02) [ENABLE] assert(address,bytes) alloc(newmem,$1000,"SaintsRow.exe"+B1D8D2) label(code) label(return) newmem: // 1 million bucks!1 mov edi,F4240 jmp return code: //mov edi,[SaintsRow.exe+2D00158] //jmp return address: jmp newmem nop return: [DISABLE] address: db bytes // mov edi,[SaintsRow.exe+2D00158] dealloc(newmem) { // ORIGINAL CODE - INJECTION POINT: SaintsRow.exe+B1D8D2 SaintsRow.exe+B1D8A2: EB 06 - jmp SaintsRow.exe+B1D8AA SaintsRow.exe+B1D8A4: 44 8B D8 - mov r11d,eax SaintsRow.exe+B1D8A7: 41 F7 DB - neg r11d SaintsRow.exe+B1D8AA: 48 8B 05 EF 55 92 04 - mov rax,[SaintsRow.exe+5442EA0] SaintsRow.exe+B1D8B1: F3 0F 10 70 38 - movss xmm6,[rax+38] SaintsRow.exe+B1D8B6: F3 0F 59 35 56 26 BF 01 - mulss xmm6,[SaintsRow.exe+270FF14] SaintsRow.exe+B1D8BE: 66 41 0F 6E C3 - movd xmm0,r11d SaintsRow.exe+B1D8C3: 0F 5B C0 - cvtdq2ps xmm0,xmm0 SaintsRow.exe+B1D8C6: F3 0F 59 05 BA 25 BF 01 - mulss xmm0,[SaintsRow.exe+270FE88] SaintsRow.exe+B1D8CE: F3 0F 5C F0 - subss xmm6,xmm0 // ---------- INJECTING HERE ---------- SaintsRow.exe+B1D8D2: 8B 3D 80 28 1E 02 - mov edi,[SaintsRow.exe+2D00158] // ---------- DONE INJECTING ---------- SaintsRow.exe+B1D8D8: E8 03 16 B6 FF - call SaintsRow.exe+67EEE0 SaintsRow.exe+B1D8DD: 41 8B DD - mov ebx,r13d SaintsRow.exe+B1D8E0: 85 C0 - test eax,eax SaintsRow.exe+B1D8E2: 41 0F 45 DF - cmovne ebx,r15d SaintsRow.exe+B1D8E6: 8B C0 - mov eax,eax SaintsRow.exe+B1D8E8: 0F 57 C0 - xorps xmm0,xmm0 SaintsRow.exe+B1D8EB: F3 48 0F 2A C0 - cvtsi2ss xmm0,rax SaintsRow.exe+B1D8F0: F3 0F 59 C6 - mulss xmm0,xmm6 SaintsRow.exe+B1D8F4: FF 15 CE 54 94 01 - call qword ptr [SaintsRow.exe+2462DC8] SaintsRow.exe+B1D8FA: F3 0F 2C C0 - cvttss2si eax,xmm0 }