Skip to content

Commit

Permalink
v12.5 update
Browse files Browse the repository at this point in the history
  • Loading branch information
argonlefou committed Jun 4, 2024
1 parent a472f26 commit 533a42b
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 90 deletions.
2 changes: 1 addition & 1 deletion DemulShooter/Games/Game_PpmPoliceTrainer2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private void SetHack_Recoil_P1()
//mov [08230900],edx
CaveMemory.Write_StrBytes("89 15 00 09 23 08");
//return
CaveMemory.Write_jmp(_P2Recoil_InjectionStruct.InjectionReturnOffset);
CaveMemory.Write_jmp(_P1Recoil_InjectionStruct.InjectionReturnOffset);

Logger.WriteLog("Adding P1 Recoil Codecave at : 0x" + CaveMemory.CaveAddress.ToString("X8"));

Expand Down
179 changes: 113 additions & 66 deletions DemulShooter/Games/Game_RwLGI3D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using DsCore.Memory;
using DsCore.RawInput;
using DsCore.Win32;
using System.Text;

namespace DemulShooter
{
Expand All @@ -25,20 +26,25 @@ class Game_RwLGI3D : Game
private UInt32 _P2_Y_Offset = 0x00000013;
private UInt32 _P2_Buttons_Offset = 0x00000009;
private NopStruct _Nop_Axis = new NopStruct(0x002FE60C, 3);
private UInt32 _Buttons_Injection_Offset = 0x002FE592;
private UInt32 _Buttons_Injection_Return_Offset = 0x002FE59A;
protected UInt32 _CalibrationValues_Injection_Offset = 0x0049DC27;
protected UInt32 _CalibrationValues_Injection_Return_Offset = 0x0049DC2D;
private InjectionStruct _Buttons_InjectionStruct = new InjectionStruct(0x002FE592, 8);
private InjectionStruct _CalibrationValues_InjectionStruct = new InjectionStruct(0x0049DC27, 6);
private UInt32 _StrlenFunction_Offset = 0x002FF3EC;

//Outputs
private UInt32 _OutputsPtr_Offset = 0x0065DA20;
private UInt32 _PlayersStructPtr_Offset = 0x008429F0;

//Custom recoil injection
private UInt32 _Recoil_Injection_Offset = 0x003518F1;
private UInt32 _Recoil_Injection_Return_Offset = 0x003518F6;
//Custom injection
private InjectionStruct _Recoil_InjectionStruct = new InjectionStruct(0x003518F1, 5);
private InjectionStruct _CurrentSequence_InjectionStruct = new InjectionStruct(0x0002615BF, 6);

//Custom Data
private UInt32 _P1_CustomRecoil_CaveAddress = 0;
private UInt32 _P2_CustomRecoil_CaveAddress = 0;
private UInt32 _CurrentSequenceStringLength = 0;
private UInt32 _CurrentSequenceString = 0;

private bool _IsAttractMode = true;

/// <summary>
/// Constructor
Expand Down Expand Up @@ -227,22 +233,10 @@ private void SetHack_Buttons()
//movzx ecx,byte ptr [esp+13]
CaveMemory.Write_StrBytes("0F B6 4C 24 13");
//Jump back
CaveMemory.Write_jmp((UInt32)_TargetProcess.MainModule.BaseAddress + _Buttons_Injection_Return_Offset);

Logger.WriteLog("Adding CodeCave at : 0x" + CaveMemory.CaveAddress.ToString("X8"));

//Code injection
IntPtr ProcessHandle = _TargetProcess.Handle;
UInt32 bytesWritten = 0;
UInt32 jumpTo = 0;
jumpTo = CaveMemory.CaveAddress - ((UInt32)_TargetProcess.MainModule.BaseAddress + _Buttons_Injection_Offset) - 5;
Buffer = new List<byte>();
Buffer.Add(0xE9);
Buffer.AddRange(BitConverter.GetBytes(jumpTo));
Buffer.Add(0x90);
Buffer.Add(0x90);
Buffer.Add(0x90);
Win32API.WriteProcessMemory(ProcessHandle, (UInt32)_TargetProcess.MainModule.BaseAddress + _Buttons_Injection_Offset, Buffer.ToArray(), (UInt32)Buffer.Count, ref bytesWritten);
CaveMemory.Write_jmp((UInt32)_TargetProcess.MainModule.BaseAddress + _Buttons_InjectionStruct.InjectionReturnOffset);

//Inject it
CaveMemory.Inject(_Buttons_InjectionStruct, "Buttons");
}

/// <summary>
Expand Down Expand Up @@ -282,30 +276,45 @@ private void SetHack_Calibration()
//mov dword_C17D28, edi
CaveMemory.Write_StrBytes("89 3D 28 7D C1 00");
//Jump back
CaveMemory.Write_jmp((UInt32)_TargetProcess.MainModule.BaseAddress + _CalibrationValues_Injection_Return_Offset);

Logger.WriteLog("Adding Calibration CodeCave at : 0x" + CaveMemory.CaveAddress.ToString("X8"));

//Code injection
IntPtr ProcessHandle = _TargetProcess.Handle;
UInt32 bytesWritten = 0;
UInt32 jumpTo = 0;
jumpTo = CaveMemory.CaveAddress - ((UInt32)_TargetProcess.MainModule.BaseAddress + _CalibrationValues_Injection_Offset) - 5;
Buffer = new List<byte>();
Buffer.Add(0xE9);
Buffer.AddRange(BitConverter.GetBytes(jumpTo));
Buffer.Add(0x90);
Win32API.WriteProcessMemory(ProcessHandle, (UInt32)_TargetProcess.MainModule.BaseAddress + _CalibrationValues_Injection_Offset, Buffer.ToArray(), (UInt32)Buffer.Count, ref bytesWritten);
CaveMemory.Write_jmp((UInt32)_TargetProcess.MainModule.BaseAddress + _CalibrationValues_InjectionStruct.InjectionReturnOffset);

//Inject it
CaveMemory.Inject(_CalibrationValues_InjectionStruct, "Calibration Values");
}

//Original game is simply setting a Motor to vibrate, so simply using this data to create or pulsed custom recoil will not be synchronized with bullets shot
//as the pulses lenght and spaceing will depend on DemulShooter output pulse config data.
//To synch recoil pulse with projectiles, this hack allows to intercept the code shooting the actual projectile to generate the pulse
private void SetHack_Output()
{
//Create Databak to store our value
CreateDataBank();
Create_OutputsDataBank();

SetHack_Recoil();
SetHack_GetCurrentSequence();
}

/// <summary>
/// Creating a zone in memory where we will save recoil status, updated by the game.
/// This memory will then be read by the game thanks to the following hacks.
/// </summary>
private void Create_OutputsDataBank()
{
Codecave CaveMemory = new Codecave(_TargetProcess, _TargetProcess.MainModule.BaseAddress);
CaveMemory.Open();
CaveMemory.Alloc(0x800);

_P1_CustomRecoil_CaveAddress = CaveMemory.CaveAddress;
_P2_CustomRecoil_CaveAddress = CaveMemory.CaveAddress + 0x04;
_CurrentSequenceStringLength = CaveMemory.CaveAddress + 0x10;
_CurrentSequenceString = CaveMemory.CaveAddress + 0x14;

Logger.WriteLog("Custom Recoil data will be stored at : 0x" + _P1_CustomRecoil_CaveAddress.ToString("X8"));
}

//Original game is simply setting a Motor to vibrate, so simply using this data to create or pulsed custom recoil will not be synchronized with bullets shot
//as the pulses lenght and spaceing will depend on DemulShooter output pulse config data.
//To synch recoil pulse with projectiles, this hack allows to intercept the code shooting the actual projectile to generate the pulse

private void SetHack_Recoil()
{
Codecave CaveMemory = new Codecave(_TargetProcess, _TargetProcess.MainModule.BaseAddress);
CaveMemory.Open();
CaveMemory.Alloc(0x800);
Expand All @@ -324,38 +333,70 @@ private void SetHack_Output()
CaveMemory.Write_StrBytes("C7 00 01 00 00 00");
//xor al,al
CaveMemory.Write_StrBytes("30 C0");
CaveMemory.Write_jmp((UInt32)_TargetProcess.MainModule.BaseAddress + _Recoil_Injection_Return_Offset);

Logger.WriteLog("Adding Recoil Codecave at : 0x" + CaveMemory.CaveAddress.ToString("X8"));
CaveMemory.Write_jmp((UInt32)_TargetProcess.MainModule.BaseAddress + _Recoil_InjectionStruct.InjectionReturnOffset);

//Code injection
IntPtr ProcessHandle = _TargetProcess.Handle;
UInt32 bytesWritten = 0;
UInt32 jumpTo = 0;
jumpTo = CaveMemory.CaveAddress - ((UInt32)_TargetProcess.MainModule.BaseAddress + _Recoil_Injection_Offset) - 5;
Buffer = new List<byte>();
Buffer.Add(0xE9);
Buffer.AddRange(BitConverter.GetBytes(jumpTo));
Win32API.WriteProcessMemory(ProcessHandle, (UInt32)_TargetProcess.MainModule.BaseAddress + _Recoil_Injection_Offset, Buffer.ToArray(), (UInt32)Buffer.Count, ref bytesWritten);

Logger.WriteLog("Output memory Hack complete !");
Logger.WriteLog("-");
//Inject it
CaveMemory.Inject(_Recoil_InjectionStruct, "Recoil");
}


/// <summary>
/// Creating a zone in memory where we will save recoil status, updated by the game.
/// This memory will then be read by the game thanks to the following hacks.
/// Get the current sequence string, this will be used later to filter when the game is in "Advertise" mode
/// </summary>
private void CreateDataBank()
private void SetHack_GetCurrentSequence()
{
Codecave CaveMemory = new Codecave(_TargetProcess, _TargetProcess.MainModule.BaseAddress);
CaveMemory.Open();
CaveMemory.Alloc(0x800);
List<Byte> Buffer = new List<Byte>();

_P1_CustomRecoil_CaveAddress = CaveMemory.CaveAddress;
_P2_CustomRecoil_CaveAddress = CaveMemory.CaveAddress + 0x04;
//mov mov eax,[esp+54]
CaveMemory.Write_StrBytes("8B 44 24 54");
//test eax, eax
CaveMemory.Write_StrBytes("85 C0");
//je Exit
CaveMemory.Write_StrBytes("74 2A");
//push eax
CaveMemory.Write_StrBytes("50");
//call strlen()
CaveMemory.Write_call((UInt32)_TargetProcess_MemoryBaseAddress + _StrlenFunction_Offset);
//add esp, 4
CaveMemory.Write_StrBytes("83 C4 04");
//push ecx
CaveMemory.Write_StrBytes("51");
//push esi
CaveMemory.Write_StrBytes("56");
//push edi
CaveMemory.Write_StrBytes("57");
//mov ecx, _CurrentSequenceStringLength
CaveMemory.Write_StrBytes("B9");
CaveMemory.Write_Bytes(BitConverter.GetBytes(_CurrentSequenceStringLength));
//mov [ecx], eax
CaveMemory.Write_StrBytes("89 01");
//mov ecx,eax
CaveMemory.Write_StrBytes("8B C8");
//inc ecx
CaveMemory.Write_StrBytes("41");
//mov mov esi,[esp+60]
CaveMemory.Write_StrBytes("8B 74 24 60");
//mov edi, _CurrentSequenceString
CaveMemory.Write_StrBytes("BF");
CaveMemory.Write_Bytes(BitConverter.GetBytes(_CurrentSequenceString));
//repe movsb
CaveMemory.Write_StrBytes("F3 A4");
//pop edi
CaveMemory.Write_StrBytes("5F");
//pop esi
CaveMemory.Write_StrBytes("5E");
//pop ecx
CaveMemory.Write_StrBytes("59");
//mov mov eax,[esp+54]
CaveMemory.Write_StrBytes("8B 44 24 54");
//test eax,eax
CaveMemory.Write_StrBytes("85 C0");

Logger.WriteLog("Custom Recoil data will be stored at : 0x" + _P1_CustomRecoil_CaveAddress.ToString("X8"));
//Inject it
CaveMemory.Inject(_CurrentSequence_InjectionStruct, "Current Sequence");
}

#endregion
Expand Down Expand Up @@ -465,7 +506,15 @@ public override void UpdateOutputValues()
_P1_Life = 0;
_P2_Life = 0;

if (P1_Status == 1)
UInt32 StrLength = BitConverter.ToUInt32(ReadBytes(_CurrentSequenceStringLength, 4), 0);
byte[] bCurrentSeq = ReadBytes(_CurrentSequenceString, StrLength);
string sCurrentSeq = System.Text.ASCIIEncoding.ASCII.GetString(bCurrentSeq);
if (sCurrentSeq.StartsWith("Adv"))
_IsAttractMode = true;
if (sCurrentSeq.StartsWith("GameSeq"))
_IsAttractMode = false;

if (!_IsAttractMode)
{
_P1_Life = (int)BitConverter.ToSingle(ReadBytes(P1_Strutc_Address + 0x20, 4), 0);
if (_P1_Life < 0)
Expand All @@ -474,9 +523,7 @@ public override void UpdateOutputValues()
//[Damaged] custom Output
if (_P1_Life < _P1_LastLife)
SetOutputValue(OutputId.P1_Damaged, 1);
}
if (P2_Status == 1)
{

_P2_Life = (int)BitConverter.ToSingle(ReadBytes(P2_Strutc_Address + 0x20, 4), 0);
if (_P2_Life < 0)
_P2_Life = 0;
Expand Down
30 changes: 10 additions & 20 deletions DemulShooter/Games/Game_WndHotdoPc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ namespace DemulShooter
{
class Game_WndHotdoPc : Game
{
private const String GAMEDATA_FOLDER = @"MemoryData\windows\hodo";

/*** MEMORY ADDRESSES **/
private UInt32 _Credits_Address = 0x2F9D5B3C;
private UInt32 _PlayerStatus_Offset = 0x0059C378;
private UInt32 _CreditsPtr_Offset = 0x005996C8;
private UInt32 _PlayerInfoPtr_Offset = 0x00599688;

//Play the "Coins" sound when adding coin
Expand All @@ -28,6 +30,7 @@ public Game_WndHotdoPc(String RomName, bool DisableInputHack, bool Verbose)
: base (RomName, "HOTD_NG", DisableInputHack, Verbose)
{
_KnownMd5Prints.Add("Typing Of The Dead SEGA Windows", "da39156a426e3f3faca25d3c8cb2b401");
_KnownMd5Prints.Add("Typing Of The Dead SEGA Windows STEAM", "9dcb7083e3e3ede186c9a809498a0d3b");

_tProcess.Start();
Logger.WriteLog("Waiting for Windows Game " + _RomName + " game to hook.....");
Expand Down Expand Up @@ -55,19 +58,7 @@ protected override void tProcess_Elapsed(Object Sender, EventArgs e)
Logger.WriteLog("Attached to Process " + _Target_Process_Name + ".exe, ProcessHandle = " + _ProcessHandle);
Logger.WriteLog(_Target_Process_Name + ".exe = 0x" + _TargetProcess_MemoryBaseAddress.ToString("X8"));
CheckExeMd5();

//Try to load the "coin" sound
try
{
String strCoinSndPath = _TargetProcess.MainModule.FileName;
strCoinSndPath = strCoinSndPath.Substring(0, strCoinSndPath.Length - 10);
strCoinSndPath += @"..\media\coin002.aif";
_SndPlayer = new SoundPlayer(strCoinSndPath);
}
catch
{
Logger.WriteLog("Unable to find/open the coin002.aif file for Hotd3");
}
ReadGameDataFromMd5Hash(GAMEDATA_FOLDER);

_ProcessHooked = true;
RaiseGameHookedEvent();
Expand Down Expand Up @@ -109,11 +100,10 @@ public override IntPtr KeyboardHookCallback(IntPtr KeyboardHookID, int nCode, In
{
if (s.scanCode == HardwareScanCode.DIK_5)
{
byte Credits = ReadByte(_Credits_Address);
UInt32 Credits_Address = ReadPtrChain((UInt32)_TargetProcess_MemoryBaseAddress + _CreditsPtr_Offset, new UInt32[] { 0x228 }) + 0x17C;// ReadByte(_Credits_Address);
byte Credits = ReadByte(Credits_Address);
Credits++;
WriteByte(_Credits_Address, Credits);
if (_SndPlayer != null)
_SndPlayer.Play();
WriteByte(Credits_Address, Credits);
}
}
}
Expand Down Expand Up @@ -146,7 +136,7 @@ public override void UpdateOutputValues()
//Player status :
//[0] = Not Playing
//[1] = Playing
UInt32 P1_Status = ReadByte((UInt32)_TargetProcess_MemoryBaseAddress + 0x0059C378);
UInt32 P1_Status = ReadByte((UInt32)_TargetProcess_MemoryBaseAddress + _PlayerStatus_Offset);

UInt32 iTemp = ReadPtr((UInt32)_TargetProcess_MemoryBaseAddress + _PlayerInfoPtr_Offset);
UInt32 PlayerInfo = 0;
Expand Down Expand Up @@ -184,7 +174,7 @@ public override void UpdateOutputValues()

SetOutputValue(OutputId.P1_Ammo, _P1_Ammo);
SetOutputValue(OutputId.P1_Life, _P1_Life);
SetOutputValue(OutputId.Credits, ReadByte(_Credits_Address));
SetOutputValue(OutputId.Credits, ReadByte(ReadPtrChain((UInt32)_TargetProcess_MemoryBaseAddress + _CreditsPtr_Offset, new UInt32[] { 0x228 }) + 0x17C));
}

#endregion
Expand Down
2 changes: 1 addition & 1 deletion DemulShooter/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
// en utilisant '*', comme indiqué ci-dessous :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("12.4.0.0")]
[assembly: AssemblyVersion("12.5.0.0")]
2 changes: 1 addition & 1 deletion DemulShooterX64/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
// en utilisant '*', comme indiqué ci-dessous :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("12.4.0.0")]
[assembly: AssemblyVersion("12.5.0.0")]
29 changes: 29 additions & 0 deletions DsCore/Memory/Codecave.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,5 +211,34 @@ public bool Write_Bytes(Byte[] Buffer)
return false;
}
}

/// <summary>
/// Create both Jump-To and Jump-Back instruction and inject the codecave in memory
/// </summary>
/// <param name="iStruct">InjectionStruct with needed offset to inject the codecave to the good paert of the game code</param>
/// <param name="sCodeCaveName">Name that will be used to log the codecave creation</param>
public void Inject(InjectionStruct iStruct, string sCodeCaveName, bool bCreateButNotInject = false)
{
//Jump back
Write_jmp((UInt32)_ModuleBaseAddress + iStruct.InjectionReturnOffset);

Logger.WriteLog("Adding " + sCodeCaveName + " CodeCave at : 0x" + _Cave_Address.ToString("X8"));

//Code injection
UInt32 bytesWritten = 0;
UInt32 jumpTo = 0;
jumpTo = _Cave_Address - ((UInt32)_ModuleBaseAddress + iStruct.InjectionOffset) - 5;
List<byte> Buffer = new List<byte>();
Buffer.Add(0xE9);
Buffer.AddRange(BitConverter.GetBytes(jumpTo));
for (int i = 0; i < iStruct.NeededNops; i++)
{
Buffer.Add(0x90);
}

//For "crash" debug purpose, sometimes I need to create the codecave to examine it, without making the game jump to it.
if (!bCreateButNotInject)
Win32API.WriteProcessMemory(_ProcessHandle, (UInt32)_ModuleBaseAddress + iStruct.InjectionOffset, Buffer.ToArray(), (UInt32)Buffer.Count, ref bytesWritten);
}
}
}
Loading

0 comments on commit 533a42b

Please sign in to comment.