mirror of
https://github.com/uberhalit/SekiroFpsUnlockAndMore.git
synced 2026-06-13 09:57:55 +00:00
FOV can be changed contiously now
added data caves fixed widescreen issue in combination with borderless
This commit is contained in:
parent
b5f1d8b73e
commit
fc06f8530e
8 changed files with 431 additions and 183 deletions
|
|
@ -213,8 +213,8 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
||||||
## Version History
|
## Version History
|
||||||
|
|
||||||
* v1.2.1.1 (2019-04-09)
|
* v1.2.1.1 (2019-04-09)
|
||||||
* Added prompt to let user decide between mouse or controller input if 'disable camera auto rotation" is used
|
* Added prompt to let user decide between mouse or controller input
|
||||||
* This selection will fix locked up-down controls (pitch) on controllers
|
* This selection will fix locked up-down controls (pitch) on controllers if 'disable camera auto rotation" is used
|
||||||
* v1.2.1 (2019-04-07)
|
* v1.2.1 (2019-04-07)
|
||||||
* Added an option to disable automatic camera rotation adjust on movement (thanks to Cielos for some offsets)
|
* Added an option to disable automatic camera rotation adjust on movement (thanks to Cielos for some offsets)
|
||||||
* Added +25% FOV option
|
* Added +25% FOV option
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,10 @@ namespace SekiroFpsUnlockAndMore
|
||||||
DATA SECTION. All resolutions are listed in memory as <int>width1 <int>height1 <int>width2 <int>height2 ...
|
DATA SECTION. All resolutions are listed in memory as <int>width1 <int>height1 <int>width2 <int>height2 ...
|
||||||
Overwrite an unused one with desired new one. Some glitches, 1920x1080 and 1280x720 works best
|
Overwrite an unused one with desired new one. Some glitches, 1920x1080 and 1280x720 works best
|
||||||
*/
|
*/
|
||||||
internal const string PATTERN_RESOLUTION_DEFAULT = "80 07 00 00 38 04 00 00"; // 1920x1080
|
internal const string PATTERN_RESOLUTION_DEFAULT = "80 07 00 00 38 04 00 00 00 08 00 00 80 04 00 00"; // 1920x1080
|
||||||
internal const string PATTERN_RESOLUTION_DEFAULT_720 = "40 06 00 00 84 03 00 00"; // 1280x720
|
internal const string PATTERN_RESOLUTION_DEFAULT_720 = "00 05 00 00 D0 02 00 00 A0 05 00 00 2A 03 00 00"; // 1280x720
|
||||||
internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE = new byte[8] { 0x80, 0x07, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00 };
|
internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE = new byte[8] { 0x80, 0x07, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00 };
|
||||||
internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE_720 = new byte[8] { 0x40, 0x06, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00 };
|
internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE_720 = new byte[8] { 0x00, 0x05, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00 };
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -128,28 +128,15 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reference pointer pFovTableEntry to FOV entry in game FOV table that gets used in FOV calculations. Overwrite pFovTableEntry address to use a higher or lower <float>fFOV from table
|
Reference pointer pFovTableEntry to FOV entry in game FOV table that gets used in FOV calculations. Overwrite pFovTableEntry address to use a higher or lower <float>fFOV from table
|
||||||
|
FOV is in radians while default is 1.0deg (0.0174533rad), to increase by 25% you'd write 1.25deg (0.0218166rad) as fFov
|
||||||
0000000140739548 | F3:0F1008 | movss xmm1,dword ptr ds:[rax] |
|
0000000140739548 | F3:0F1008 | movss xmm1,dword ptr ds:[rax] |
|
||||||
000000014073954C | F3:0F590D 0CE79B02 | mulss xmm1,dword ptr ds:[1430F7C60] | pFovTableEntry->fFov
|
000000014073954C | F3:0F590D 0CE79B02 | mulss xmm1,dword ptr ds:[1430F7C60] | pFovTableEntry->fFov
|
||||||
|
0000000140739554 | F3:0F5C4E 50 | subss xmm1,dword ptr ds:[rsi+50] |
|
||||||
*/
|
*/
|
||||||
// credits to 'jackfuste' for original offset
|
// credits to 'jackfuste' for original offset
|
||||||
internal const string PATTERN_FOVSETTING = "F3 0F 10 08 F3 0F 59 0D ?? ?? 9B 02";
|
internal const string PATTERN_FOVSETTING = "F3 0F 10 08 F3 0F 59 0D ?? ?? ?? ?? F3 0F 5C 4E";
|
||||||
internal const int PATTERN_FOVSETTING_OFFSET = 8;
|
internal const int PATTERN_FOVSETTING_OFFSET = 8;
|
||||||
/**
|
internal const float PATCH_FOVSETTING_DISABLE = 0.0174533f; // Rad2Deg -> 1°
|
||||||
00000001430F7C60
|
|
||||||
Key: Patch to pFovTableEntry (last 2 bytes)
|
|
||||||
Value: Value resolve in float table from pFovTableEntry->fFov
|
|
||||||
*/
|
|
||||||
internal static readonly Dictionary<byte[], string> PATCH_FOVSETTING_MATRIX = new Dictionary<byte[], string>
|
|
||||||
{
|
|
||||||
{ new byte[2] {0x00, 0xE7}, "- 50%" },
|
|
||||||
{ new byte[2] {0x04, 0xE7}, "- 10%" },
|
|
||||||
{ new byte[2] {0x10, 0xE7}, "+ 15%" },
|
|
||||||
{ new byte[2] {0x42, 0x9B}, "+ 25%" },
|
|
||||||
{ new byte[2] {0x14, 0xE7}, "+ 40%" },
|
|
||||||
{ new byte[2] {0x18, 0xE7}, "+ 75%" },
|
|
||||||
{ new byte[2] {0x1C, 0xE7}, "+ 90%" }
|
|
||||||
};
|
|
||||||
internal static readonly byte[] PATCH_FOVSETTING_DISABLE = new byte[2] { 0x0C, 0xE7 }; // + 0%
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SekiroFpsUnlockAndMore"
|
xmlns:local="clr-namespace:SekiroFpsUnlockAndMore"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Sekiro FPS Unlocker and more v1.2.1" Width="Auto" Height="Auto" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize" Loaded="Window_Loaded" Closing="Window_Closing">
|
Title="Sekiro FPS Unlocker and more v1.2.2" Width="Auto" Height="Auto" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize" Loaded="Window_Loaded" Closing="Window_Closing">
|
||||||
|
|
||||||
<Grid Background="#FFF9F9F9">
|
<Grid Background="#FFF9F9F9">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
|
|
@ -21,8 +21,11 @@
|
||||||
<TextBox x:Name="tbWidth" DockPanel.Dock="Right" Margin="0,0,0,0" Width="50" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="2560" MaxLength="4" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
|
<TextBox x:Name="tbWidth" DockPanel.Dock="Right" Margin="0,0,0,0" Width="50" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="2560" MaxLength="4" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0,5,0,0" LastChildFill="False">
|
<DockPanel Margin="0,5,0,0" LastChildFill="False">
|
||||||
<CheckBox x:Name="cbFov" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Increase FOV by:" Checked="CbFov_Check_Handler" Unchecked="CbFov_Check_Handler" />
|
<CheckBox x:Name="cbFov" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Change FOV by (%):" Checked="CbFov_Check_Handler" Unchecked="CbFov_Check_Handler" />
|
||||||
<ComboBox x:Name="cbSelectFov" DockPanel.Dock="Right" Margin="0,0,0,0" Width="116" Height="25" FontSize="14 px" SelectedValuePath="Key" DisplayMemberPath="Value" DropDownClosed="CbSelectFov_DropDownClosed"/>
|
<Button x:Name="bFovHigher" DockPanel.Dock="Right" Content=">" Margin="0,0,0,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BFovHigher_Click" />
|
||||||
|
<TextBox x:Name="tbFov" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="25" TextAlignment="Center" MaxLength="3" PreviewTextInput="SignedNumeric_PreviewTextInput" DataObject.Pasting="SignedNumeric_PastingHandler" />
|
||||||
|
<Button x:Name="bFovLower" DockPanel.Dock="Right" Content="<" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BFovLower_Click" />
|
||||||
|
<Button x:Name="bFov0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="27" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BFov0_Click" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<StackPanel Margin="0,5,0,0" Orientation="Horizontal">
|
<StackPanel Margin="0,5,0,0" Orientation="Horizontal">
|
||||||
<CheckBox x:Name="cbBorderless" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Borderless window" ToolTip="To enable this set 'Windowed' mode in game options first." IsEnabled="False" Checked="CbBorderless_Checked" Unchecked="CbBorderless_Unchecked"/>
|
<CheckBox x:Name="cbBorderless" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Borderless window" ToolTip="To enable this set 'Windowed' mode in game options first." IsEnabled="False" Checked="CbBorderless_Checked" Unchecked="CbBorderless_Unchecked"/>
|
||||||
|
|
@ -35,27 +38,19 @@
|
||||||
<StackPanel Width="Auto" Height="Auto">
|
<StackPanel Width="Auto" Height="Auto">
|
||||||
<DockPanel Margin="0,3,0,0" LastChildFill="False">
|
<DockPanel Margin="0,3,0,0" LastChildFill="False">
|
||||||
<CheckBox x:Name="cbGameSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Game speed (%):" ToolTip="Increase or decrease. Can potentially crash the game in cutscenes, use with caution." Checked="CbGameSpeed_Check_Handler" Unchecked="CbGameSpeed_Check_Handler" />
|
<CheckBox x:Name="cbGameSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Game speed (%):" ToolTip="Increase or decrease. Can potentially crash the game in cutscenes, use with caution." Checked="CbGameSpeed_Check_Handler" Unchecked="CbGameSpeed_Check_Handler" />
|
||||||
<Button x:Name="bGs100" DockPanel.Dock="Right" Content="100" Margin="0,0,0,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
<Button x:Name="bGs100" DockPanel.Dock="Right" Content="100" Margin="0,0,0,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BGs100_Click" />
|
||||||
Focusable="False" Click="BGs100_Click" />
|
<Button x:Name="bGsHigher" DockPanel.Dock="Right" Content=">" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BGsHigher_Click" />
|
||||||
<Button x:Name="bGsHigher" DockPanel.Dock="Right" Content=">" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
|
||||||
Focusable="False" Click="BGsHigher_Click" />
|
|
||||||
<TextBox x:Name="tbGameSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
|
<TextBox x:Name="tbGameSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
|
||||||
<Button x:Name="bGsLower" DockPanel.Dock="Right" Content="<" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
<Button x:Name="bGsLower" DockPanel.Dock="Right" Content="<" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BGsLower_Click" />
|
||||||
Focusable="False" Click="BGsLower_Click" />
|
<Button x:Name="bGs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BGs0_Click" />
|
||||||
<Button x:Name="bGs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
|
||||||
Focusable="False" Click="BGs0_Click" />
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<DockPanel Margin="0,5,0,0" LastChildFill="False">
|
<DockPanel Margin="0,5,0,0" LastChildFill="False">
|
||||||
<CheckBox x:Name="cbPlayerSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Player speed (%):" ToolTip="Increase or decrease. To enable this start the game and load a save, then tick the checkbox. Can potentially crash the game in cutscenes, use with caution." Checked="CbPlayerSpeed_Check_Handler" Unchecked="CbPlayerSpeed_Check_Handler" />
|
<CheckBox x:Name="cbPlayerSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Player speed (%):" ToolTip="Increase or decrease. To enable this start the game and load a save, then tick the checkbox. Can potentially crash the game in cutscenes, use with caution." Checked="CbPlayerSpeed_Check_Handler" Unchecked="CbPlayerSpeed_Check_Handler" />
|
||||||
<Button x:Name="bPs100" DockPanel.Dock="Right" Content="100" Margin="0,0,0,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
<Button x:Name="bPs100" DockPanel.Dock="Right" Content="100" Margin="0,0,0,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BPs100_Click" />
|
||||||
Focusable="False" Click="BPs100_Click" />
|
<Button x:Name="bPsHigher" DockPanel.Dock="Right" Content=">" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BPsHigher_Click" />
|
||||||
<Button x:Name="bPsHigher" DockPanel.Dock="Right" Content=">" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
|
||||||
Focusable="False" Click="BPsHigher_Click" />
|
|
||||||
<TextBox x:Name="tbPlayerSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
|
<TextBox x:Name="tbPlayerSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
|
||||||
<Button x:Name="bPsLower" DockPanel.Dock="Right" Content="<" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
<Button x:Name="bPsLower" DockPanel.Dock="Right" Content="<" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BPsLower_Click" />
|
||||||
Focusable="False" Click="BPsLower_Click" />
|
<Button x:Name="bPs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Focusable="False" Click="BPs0_Click" />
|
||||||
<Button x:Name="bPs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
|
||||||
Focusable="False" Click="BPs0_Click" />
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -83,7 +78,7 @@
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Label HorizontalAlignment="Right" FontSize="12 px">
|
<Label HorizontalAlignment="Right" FontSize="12 px">
|
||||||
<Hyperlink NavigateUri="https://github.com/uberhalit/SekiroFpsUnlockAndMore" RequestNavigate="Hyperlink_RequestNavigate">
|
<Hyperlink NavigateUri="https://github.com/uberhalit/SekiroFpsUnlockAndMore" RequestNavigate="Hyperlink_RequestNavigate">
|
||||||
v1.2.1 - by uberhalit
|
v1.2.2 - by uberhalit
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
</Label>
|
</Label>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,13 @@ namespace SekiroFpsUnlockAndMore
|
||||||
internal long _offset_resolution = 0x0;
|
internal long _offset_resolution = 0x0;
|
||||||
internal long _offset_resolution_default = 0x0;
|
internal long _offset_resolution_default = 0x0;
|
||||||
internal long _offset_resolution_scaling_fix = 0x0;
|
internal long _offset_resolution_scaling_fix = 0x0;
|
||||||
internal long _offset_fovsetting = 0x0;
|
|
||||||
internal long _offset_total_kills = 0x0;
|
internal long _offset_total_kills = 0x0;
|
||||||
internal long _offset_player_deaths = 0x0;
|
internal long _offset_player_deaths = 0x0;
|
||||||
internal long _offset_timescale = 0x0;
|
internal long _offset_timescale = 0x0;
|
||||||
internal long _offset_timescale_player = 0x0;
|
internal long _offset_timescale_player = 0x0;
|
||||||
internal long _offset_timescale_player_pointer_start = 0x0;
|
internal long _offset_timescale_player_pointer_start = 0x0;
|
||||||
|
|
||||||
internal CodeCaveGenerator _codeCaveGenerator;
|
internal MemoryCaveGenerator _memoryCaveGenerator;
|
||||||
internal SettingsService _settingsService;
|
internal SettingsService _settingsService;
|
||||||
internal StatusViewModel _statusViewModel = new StatusViewModel();
|
internal StatusViewModel _statusViewModel = new StatusViewModel();
|
||||||
|
|
||||||
|
|
@ -49,10 +48,12 @@ namespace SekiroFpsUnlockAndMore
|
||||||
internal string _killCounterPath;
|
internal string _killCounterPath;
|
||||||
internal bool _retryAccess = true;
|
internal bool _retryAccess = true;
|
||||||
internal bool _use_resolution_720 = false;
|
internal bool _use_resolution_720 = false;
|
||||||
internal bool _codeCavesGenerated = false;
|
internal bool _codeCave_camadjust = false;
|
||||||
|
internal bool _dataCave_fovsetting = false;
|
||||||
internal bool _statLoggingEnabled = false;
|
internal bool _statLoggingEnabled = false;
|
||||||
internal RECT _windowRect;
|
internal RECT _windowRect;
|
||||||
|
|
||||||
|
internal const string _DATACAVE_FOV_POINTER = "fovPointer";
|
||||||
internal const string _CODECAVE_CAMADJUST_PITCH = "camAdjustPitch";
|
internal const string _CODECAVE_CAMADJUST_PITCH = "camAdjustPitch";
|
||||||
internal const string _CODECAVE_CAMADJUST_YAW_Z = "camAdjustYawZ";
|
internal const string _CODECAVE_CAMADJUST_YAW_Z = "camAdjustYawZ";
|
||||||
internal const string _CODECAVE_CAMADJUST_PITCH_XY = "camAdjustPitchXY";
|
internal const string _CODECAVE_CAMADJUST_PITCH_XY = "camAdjustPitchXY";
|
||||||
|
|
@ -81,9 +82,6 @@ namespace SekiroFpsUnlockAndMore
|
||||||
_deathCounterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\DeathCounter.txt";
|
_deathCounterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\DeathCounter.txt";
|
||||||
_killCounterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\TotalKillsCounter.txt";
|
_killCounterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\TotalKillsCounter.txt";
|
||||||
|
|
||||||
this.cbSelectFov.ItemsSource = GameData.PATCH_FOVSETTING_MATRIX;
|
|
||||||
this.cbSelectFov.SelectedIndex = 2;
|
|
||||||
|
|
||||||
LoadConfiguration();
|
LoadConfiguration();
|
||||||
|
|
||||||
if (_settingsService.ApplicationSettings.cameraAdjustNotify)
|
if (_settingsService.ApplicationSettings.cameraAdjustNotify)
|
||||||
|
|
@ -164,7 +162,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
this.tbWidth.Text = _settingsService.ApplicationSettings.tbWidth.ToString();
|
this.tbWidth.Text = _settingsService.ApplicationSettings.tbWidth.ToString();
|
||||||
this.tbHeight.Text = _settingsService.ApplicationSettings.tbHeight.ToString();
|
this.tbHeight.Text = _settingsService.ApplicationSettings.tbHeight.ToString();
|
||||||
this.cbFov.IsChecked = _settingsService.ApplicationSettings.cbFov;
|
this.cbFov.IsChecked = _settingsService.ApplicationSettings.cbFov;
|
||||||
this.cbSelectFov.SelectedIndex = _settingsService.ApplicationSettings.cbSelectFov;
|
this.tbFov.Text = _settingsService.ApplicationSettings.tbFov.ToString();
|
||||||
this.cbBorderless.IsChecked = _settingsService.ApplicationSettings.cbBorderless;
|
this.cbBorderless.IsChecked = _settingsService.ApplicationSettings.cbBorderless;
|
||||||
this.cbBorderlessStretch.IsChecked = _settingsService.ApplicationSettings.cbBorderlessStretch;
|
this.cbBorderlessStretch.IsChecked = _settingsService.ApplicationSettings.cbBorderlessStretch;
|
||||||
this.cbCamAdjust.IsChecked = _settingsService.ApplicationSettings.cbCamAdjust;
|
this.cbCamAdjust.IsChecked = _settingsService.ApplicationSettings.cbCamAdjust;
|
||||||
|
|
@ -187,7 +185,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
_settingsService.ApplicationSettings.tbWidth = Convert.ToInt32(this.tbWidth.Text);
|
_settingsService.ApplicationSettings.tbWidth = Convert.ToInt32(this.tbWidth.Text);
|
||||||
_settingsService.ApplicationSettings.tbHeight = Convert.ToInt32(this.tbHeight.Text);
|
_settingsService.ApplicationSettings.tbHeight = Convert.ToInt32(this.tbHeight.Text);
|
||||||
_settingsService.ApplicationSettings.cbFov = this.cbFov.IsChecked == true;
|
_settingsService.ApplicationSettings.cbFov = this.cbFov.IsChecked == true;
|
||||||
_settingsService.ApplicationSettings.cbSelectFov = this.cbSelectFov.SelectedIndex;
|
_settingsService.ApplicationSettings.tbFov = Convert.ToInt32(this.tbFov.Text);
|
||||||
_settingsService.ApplicationSettings.cbBorderless = this.cbBorderless.IsChecked == true;
|
_settingsService.ApplicationSettings.cbBorderless = this.cbBorderless.IsChecked == true;
|
||||||
_settingsService.ApplicationSettings.cbBorderlessStretch = this.cbBorderlessStretch.IsChecked == true;
|
_settingsService.ApplicationSettings.cbBorderlessStretch = this.cbBorderlessStretch.IsChecked == true;
|
||||||
_settingsService.ApplicationSettings.cbCamAdjust = this.cbCamAdjust.IsChecked == true;
|
_settingsService.ApplicationSettings.cbCamAdjust = this.cbCamAdjust.IsChecked == true;
|
||||||
|
|
@ -287,7 +285,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
private void ReadGame(object sender, DoWorkEventArgs doWorkEventArgs)
|
private void ReadGame(object sender, DoWorkEventArgs doWorkEventArgs)
|
||||||
{
|
{
|
||||||
PatternScan patternScan = new PatternScan(_gameAccessHwnd, _gameProc.MainModule);
|
PatternScan patternScan = new PatternScan(_gameAccessHwnd, _gameProc.MainModule);
|
||||||
_codeCaveGenerator = new CodeCaveGenerator(_gameAccessHwnd, _gameProc.MainModule.BaseAddress.ToInt64());
|
_memoryCaveGenerator = new MemoryCaveGenerator(_gameAccessHwnd, _gameProc.MainModule.BaseAddress.ToInt64());
|
||||||
|
|
||||||
_offset_framelock = patternScan.FindPattern(GameData.PATTERN_FRAMELOCK) + GameData.PATTERN_FRAMELOCK_OFFSET;
|
_offset_framelock = patternScan.FindPattern(GameData.PATTERN_FRAMELOCK) + GameData.PATTERN_FRAMELOCK_OFFSET;
|
||||||
Debug.WriteLine("fFrameTick found at: 0x" + _offset_framelock.ToString("X"));
|
Debug.WriteLine("fFrameTick found at: 0x" + _offset_framelock.ToString("X"));
|
||||||
|
|
@ -324,10 +322,14 @@ namespace SekiroFpsUnlockAndMore
|
||||||
_offset_resolution = 0x0;
|
_offset_resolution = 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_offset_fovsetting = patternScan.FindPattern(GameData.PATTERN_FOVSETTING) + GameData.PATTERN_FOVSETTING_OFFSET;
|
long lpFovPointer = patternScan.FindPattern(GameData.PATTERN_FOVSETTING) + GameData.PATTERN_FOVSETTING_OFFSET;
|
||||||
Debug.WriteLine("pFovTableEntry found at: 0x" + _offset_fovsetting.ToString("X"));
|
Debug.WriteLine("lpFovPointer found at: 0x" + lpFovPointer.ToString("X"));
|
||||||
if (!IsValidAddress(_offset_fovsetting))
|
if (IsValidAddress(lpFovPointer))
|
||||||
_offset_fovsetting = 0x0;
|
{
|
||||||
|
if (_memoryCaveGenerator.CreateNewDataCave(_DATACAVE_FOV_POINTER, lpFovPointer, BitConverter.GetBytes(GameData.PATCH_FOVSETTING_DISABLE), PointerStyle.dwRelative))
|
||||||
|
_dataCave_fovsetting = true;
|
||||||
|
Debug.WriteLine("lpFovPointer data cave at: 0x" + _memoryCaveGenerator.GetDataCaveAddressByName(_DATACAVE_FOV_POINTER).ToString("X"));
|
||||||
|
}
|
||||||
|
|
||||||
long ref_lpPlayerStatsRelated = patternScan.FindPattern(GameData.PATTERN_PLAYER_DEATHS) + GameData.PATTERN_PLAYER_DEATHS_OFFSET;
|
long ref_lpPlayerStatsRelated = patternScan.FindPattern(GameData.PATTERN_PLAYER_DEATHS) + GameData.PATTERN_PLAYER_DEATHS_OFFSET;
|
||||||
Debug.WriteLine("ref_lpPlayerStatsRelated found at: 0x" + ref_lpPlayerStatsRelated.ToString("X"));
|
Debug.WriteLine("ref_lpPlayerStatsRelated found at: 0x" + ref_lpPlayerStatsRelated.ToString("X"));
|
||||||
|
|
@ -415,17 +417,17 @@ namespace SekiroFpsUnlockAndMore
|
||||||
{
|
{
|
||||||
List<bool> results = new List<bool>
|
List<bool> results = new List<bool>
|
||||||
{
|
{
|
||||||
_codeCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_PITCH, lpCamAdjustPitch, GameData.INJECT_CAMADJUST_PITCH_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_PITCH_SHELLCODE),
|
_memoryCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_PITCH, lpCamAdjustPitch, GameData.INJECT_CAMADJUST_PITCH_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_PITCH_SHELLCODE),
|
||||||
_codeCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_YAW_Z, lpCamAdjustYawZ, GameData.INJECT_CAMADJUST_YAW_Z_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_YAW_Z_SHELLCODE),
|
_memoryCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_YAW_Z, lpCamAdjustYawZ, GameData.INJECT_CAMADJUST_YAW_Z_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_YAW_Z_SHELLCODE),
|
||||||
_codeCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_PITCH_XY, lpCamAdjustPitchXY, GameData.INJECT_CAMADJUST_PITCH_XY_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_PITCH_XY_SHELLCODE),
|
_memoryCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_PITCH_XY, lpCamAdjustPitchXY, GameData.INJECT_CAMADJUST_PITCH_XY_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_PITCH_XY_SHELLCODE),
|
||||||
_codeCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_YAW_XY, lpCamAdjustYawXY, GameData.INJECT_CAMADJUST_YAW_XY_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_YAW_XY_SHELLCODE)
|
_memoryCaveGenerator.CreateNewCodeCave(_CODECAVE_CAMADJUST_YAW_XY, lpCamAdjustYawXY, GameData.INJECT_CAMADJUST_YAW_XY_OVERWRITE_LENGTH, GameData.INJECT_CAMADJUST_YAW_XY_SHELLCODE)
|
||||||
};
|
};
|
||||||
Debug.WriteLine("lpCamAdjustPitch code cave at: 0x" + _codeCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_PITCH).ToString("X"));
|
Debug.WriteLine("lpCamAdjustPitch code cave at: 0x" + _memoryCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_PITCH).ToString("X"));
|
||||||
Debug.WriteLine("lpCamAdjustYawZ code cave at: 0x" + _codeCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_YAW_Z).ToString("X"));
|
Debug.WriteLine("lpCamAdjustYawZ code cave at: 0x" + _memoryCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_YAW_Z).ToString("X"));
|
||||||
Debug.WriteLine("lpCamAdjustPitchXY code cave at: 0x" + _codeCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_PITCH_XY).ToString("X"));
|
Debug.WriteLine("lpCamAdjustPitchXY code cave at: 0x" + _memoryCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_PITCH_XY).ToString("X"));
|
||||||
Debug.WriteLine("lpCamAdjustYawXY code cave at: 0x" + _codeCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_YAW_XY).ToString("X"));
|
Debug.WriteLine("lpCamAdjustYawXY code cave at: 0x" + _memoryCaveGenerator.GetCodeCaveAddressByName(_CODECAVE_CAMADJUST_YAW_XY).ToString("X"));
|
||||||
if (results.IndexOf(false) < 0)
|
if (results.IndexOf(false) < 0)
|
||||||
_codeCavesGenerated = true;
|
_codeCave_camadjust = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -448,7 +450,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
this.cbFramelock.IsEnabled = false;
|
this.cbFramelock.IsEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int)SystemParameters.PrimaryScreenWidth < 1281) _use_resolution_720 = true;
|
if ((int)SystemParameters.PrimaryScreenWidth < 1920) _use_resolution_720 = true;
|
||||||
if (_offset_resolution_default == 0x0)
|
if (_offset_resolution_default == 0x0)
|
||||||
{
|
{
|
||||||
UpdateStatus("default resolution not found...", Brushes.Red);
|
UpdateStatus("default resolution not found...", Brushes.Red);
|
||||||
|
|
@ -468,10 +470,10 @@ namespace SekiroFpsUnlockAndMore
|
||||||
this.cbAddResolution.IsEnabled = false;
|
this.cbAddResolution.IsEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_offset_fovsetting == 0x0)
|
if (!_dataCave_fovsetting)
|
||||||
{
|
{
|
||||||
UpdateStatus("fov table not found...", Brushes.Red);
|
UpdateStatus("could not create FOV table...", Brushes.Red);
|
||||||
LogToFile("fov table not found...");
|
LogToFile("could not create FOV table...");
|
||||||
this.cbFov.IsEnabled = false;
|
this.cbFov.IsEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -492,12 +494,12 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
this.cbBorderless.IsEnabled = true;
|
this.cbBorderless.IsEnabled = true;
|
||||||
|
|
||||||
if (!_codeCavesGenerated)
|
if (!_codeCave_camadjust)
|
||||||
{
|
{
|
||||||
UpdateStatus("cam adjust not found...", Brushes.Red);
|
UpdateStatus("cam adjust not found...", Brushes.Red);
|
||||||
LogToFile("cam adjust not found...");
|
LogToFile("cam adjust not found...");
|
||||||
}
|
}
|
||||||
this.cbCamAdjust.IsEnabled = _codeCavesGenerated;
|
this.cbCamAdjust.IsEnabled = _codeCave_camadjust;
|
||||||
|
|
||||||
if (_offset_timescale == 0x0)
|
if (_offset_timescale == 0x0)
|
||||||
{
|
{
|
||||||
|
|
@ -569,14 +571,15 @@ namespace SekiroFpsUnlockAndMore
|
||||||
_offset_resolution = 0x0;
|
_offset_resolution = 0x0;
|
||||||
_offset_resolution_default = 0x0;
|
_offset_resolution_default = 0x0;
|
||||||
_offset_resolution_scaling_fix = 0x0;
|
_offset_resolution_scaling_fix = 0x0;
|
||||||
_offset_fovsetting = 0x0;
|
|
||||||
_offset_player_deaths = 0x0;
|
_offset_player_deaths = 0x0;
|
||||||
_offset_total_kills = 0x0;
|
_offset_total_kills = 0x0;
|
||||||
_offset_timescale = 0x0;
|
_offset_timescale = 0x0;
|
||||||
_offset_timescale_player = 0x0;
|
_offset_timescale_player = 0x0;
|
||||||
_offset_timescale_player_pointer_start = 0x0;
|
_offset_timescale_player_pointer_start = 0x0;
|
||||||
_codeCaveGenerator.ClearCodeCaves();
|
_dataCave_fovsetting = false;
|
||||||
_codeCaveGenerator = null;
|
_codeCave_camadjust = false;
|
||||||
|
_memoryCaveGenerator.ClearCaves();
|
||||||
|
_memoryCaveGenerator = null;
|
||||||
this.cbFramelock.IsEnabled = true;
|
this.cbFramelock.IsEnabled = true;
|
||||||
this.cbAddResolution.IsEnabled = true;
|
this.cbAddResolution.IsEnabled = true;
|
||||||
this.cbFov.IsEnabled = true;
|
this.cbFov.IsEnabled = true;
|
||||||
|
|
@ -647,11 +650,12 @@ namespace SekiroFpsUnlockAndMore
|
||||||
if (!this.cbAddResolution.IsEnabled || _offset_resolution == 0x0 || _offset_resolution_default == 0x0 || _offset_resolution_scaling_fix == 0x0 || !CanPatchGame()) return false;
|
if (!this.cbAddResolution.IsEnabled || _offset_resolution == 0x0 || _offset_resolution_default == 0x0 || _offset_resolution_scaling_fix == 0x0 || !CanPatchGame()) return false;
|
||||||
if (this.cbAddResolution.IsChecked == true)
|
if (this.cbAddResolution.IsChecked == true)
|
||||||
{
|
{
|
||||||
|
this.cbBorderless.IsChecked = false;
|
||||||
bool isNumber = Int32.TryParse(this.tbWidth.Text, out int width);
|
bool isNumber = Int32.TryParse(this.tbWidth.Text, out int width);
|
||||||
if (width < 800 || !isNumber)
|
if (width < 800 || !isNumber)
|
||||||
{
|
{
|
||||||
this.tbWidth.Text = "2560";
|
this.tbWidth.Text = "800";
|
||||||
width = 2560;
|
width = 800;
|
||||||
}
|
}
|
||||||
else if (width > 5760)
|
else if (width > 5760)
|
||||||
{
|
{
|
||||||
|
|
@ -661,8 +665,8 @@ namespace SekiroFpsUnlockAndMore
|
||||||
isNumber = Int32.TryParse(this.tbHeight.Text, out int height);
|
isNumber = Int32.TryParse(this.tbHeight.Text, out int height);
|
||||||
if (height < 450 || !isNumber)
|
if (height < 450 || !isNumber)
|
||||||
{
|
{
|
||||||
this.tbHeight.Text = "1080";
|
this.tbHeight.Text = "450";
|
||||||
height = 1080;
|
height = 450;
|
||||||
}
|
}
|
||||||
else if (height > 2160)
|
else if (height > 2160)
|
||||||
{
|
{
|
||||||
|
|
@ -675,6 +679,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
}
|
}
|
||||||
else if (this.cbAddResolution.IsChecked == false)
|
else if (this.cbAddResolution.IsChecked == false)
|
||||||
{
|
{
|
||||||
|
this.cbBorderless.IsChecked = false;
|
||||||
WriteBytes(_gameAccessHwndStatic, _offset_resolution_default, !_use_resolution_720 ? GameData.PATCH_RESOLUTION_DEFAULT_DISABLE : GameData.PATCH_RESOLUTION_DEFAULT_DISABLE_720);
|
WriteBytes(_gameAccessHwndStatic, _offset_resolution_default, !_use_resolution_720 ? GameData.PATCH_RESOLUTION_DEFAULT_DISABLE : GameData.PATCH_RESOLUTION_DEFAULT_DISABLE_720);
|
||||||
WriteBytes(_gameAccessHwndStatic, _offset_resolution_scaling_fix, GameData.PATCH_RESOLUTION_SCALING_FIX_DISABLE);
|
WriteBytes(_gameAccessHwndStatic, _offset_resolution_scaling_fix, GameData.PATCH_RESOLUTION_SCALING_FIX_DISABLE);
|
||||||
if (showStatus) UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White);
|
if (showStatus) UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White);
|
||||||
|
|
@ -691,15 +696,28 @@ namespace SekiroFpsUnlockAndMore
|
||||||
/// <param name="showStatus">Determines if status should be updated from within method, default is true.</param>
|
/// <param name="showStatus">Determines if status should be updated from within method, default is true.</param>
|
||||||
private bool PatchFov(bool showStatus = true)
|
private bool PatchFov(bool showStatus = true)
|
||||||
{
|
{
|
||||||
if (!this.cbFov.IsEnabled || _offset_fovsetting == 0x0 || !CanPatchGame()) return false;
|
if (!this.cbFov.IsEnabled || !_dataCave_fovsetting|| !CanPatchGame()) return false;
|
||||||
if (this.cbFov.IsChecked == true)
|
if (this.cbFov.IsChecked == true)
|
||||||
{
|
{
|
||||||
byte[] fovByte = ((KeyValuePair<byte[], string>)this.cbSelectFov.SelectedItem).Key;
|
bool isNumber = Int32.TryParse(this.tbFov.Text, out int fovIncrease);
|
||||||
WriteBytes(_gameAccessHwndStatic, _offset_fovsetting, fovByte);
|
if (fovIncrease < -95 || !isNumber)
|
||||||
|
{
|
||||||
|
this.tbFov.Text = "-95";
|
||||||
|
fovIncrease = -95;
|
||||||
|
}
|
||||||
|
else if (fovIncrease > 95)
|
||||||
|
{
|
||||||
|
this.tbFov.Text = "95";
|
||||||
|
fovIncrease = 95;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fovValue = (float)(Math.PI / 180) * ((fovIncrease / 100.0f) + 1); // convert change in %degree to radians
|
||||||
|
_memoryCaveGenerator.UpdateDataCaveValueByName(_DATACAVE_FOV_POINTER, BitConverter.GetBytes(fovValue));
|
||||||
|
_memoryCaveGenerator.ActivateDataCaveByName(_DATACAVE_FOV_POINTER);
|
||||||
}
|
}
|
||||||
else if (this.cbFov.IsChecked == false)
|
else if (this.cbFov.IsChecked == false)
|
||||||
{
|
{
|
||||||
WriteBytes(_gameAccessHwndStatic, _offset_fovsetting, GameData.PATCH_FOVSETTING_DISABLE);
|
_memoryCaveGenerator.DeactivateDataCaveByName(_DATACAVE_FOV_POINTER);
|
||||||
if (showStatus) UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White);
|
if (showStatus) UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -723,8 +741,6 @@ namespace SekiroFpsUnlockAndMore
|
||||||
this.cbBorderless.IsChecked = false;
|
this.cbBorderless.IsChecked = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!IsBorderless(_gameHwnd))
|
if (!IsBorderless(_gameHwnd))
|
||||||
GetWindowRect(_gameHwnd, out _windowRect);
|
GetWindowRect(_gameHwnd, out _windowRect);
|
||||||
int width = Read<Int32>(_gameAccessHwnd, _offset_resolution);
|
int width = Read<Int32>(_gameAccessHwnd, _offset_resolution);
|
||||||
|
|
@ -735,7 +751,6 @@ namespace SekiroFpsUnlockAndMore
|
||||||
else
|
else
|
||||||
SetWindowBorderless(_gameHwnd, width, height, _windowRect.Left, _windowRect.Top);
|
SetWindowBorderless(_gameHwnd, width, height, _windowRect.Left, _windowRect.Top);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (this.cbBorderless.IsChecked == false && IsBorderless(_gameHwnd))
|
else if (this.cbBorderless.IsChecked == false && IsBorderless(_gameHwnd))
|
||||||
{
|
{
|
||||||
if (_windowRect.Bottom > 0)
|
if (_windowRect.Bottom > 0)
|
||||||
|
|
@ -868,7 +883,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InjectToGame()
|
private void InjectToGame()
|
||||||
{
|
{
|
||||||
if (!CanPatchGame() || !_codeCavesGenerated) return;
|
if (!CanPatchGame() || !_codeCave_camadjust) return;
|
||||||
|
|
||||||
if (this.cbCamAdjust.IsChecked == true)
|
if (this.cbCamAdjust.IsChecked == true)
|
||||||
{
|
{
|
||||||
|
|
@ -896,20 +911,20 @@ namespace SekiroFpsUnlockAndMore
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cbCamAdjust.IsEnabled = false;
|
this.cbCamAdjust.IsEnabled = false;
|
||||||
_codeCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH);
|
_memoryCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH);
|
||||||
_codeCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_Z);
|
_memoryCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_Z);
|
||||||
if (!_settingsService.ApplicationSettings.peasantInput)
|
if (!_settingsService.ApplicationSettings.peasantInput)
|
||||||
_codeCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH_XY); // BREAKS PITCH AND OTHER CONTROLS ON CONTROLLERS
|
_memoryCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH_XY); // BREAKS PITCH AND OTHER CONTROLS ON CONTROLLERS
|
||||||
_codeCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_XY);
|
_memoryCaveGenerator.ActivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_XY);
|
||||||
this.cbCamAdjust.IsEnabled = true;
|
this.cbCamAdjust.IsEnabled = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.cbCamAdjust.IsEnabled = false;
|
this.cbCamAdjust.IsEnabled = false;
|
||||||
_codeCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH);
|
_memoryCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH);
|
||||||
_codeCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_Z);
|
_memoryCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_Z);
|
||||||
_codeCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH_XY);
|
_memoryCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_PITCH_XY);
|
||||||
_codeCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_XY);
|
_memoryCaveGenerator.DeactivateCodeCaveByName(_CODECAVE_CAMADJUST_YAW_XY);
|
||||||
this.cbCamAdjust.IsEnabled = true;
|
this.cbCamAdjust.IsEnabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1131,6 +1146,16 @@ namespace SekiroFpsUnlockAndMore
|
||||||
return Regex.IsMatch(text, "[^0-9]+");
|
return Regex.IsMatch(text, "[^0-9]+");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check whether input is (signed) numeric only.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The text to check.</param>
|
||||||
|
/// <returns>True if input is (signed) numeric only.</returns>
|
||||||
|
private static bool IsSignedNumericInput(string text)
|
||||||
|
{
|
||||||
|
return Regex.IsMatch(text, "[-+]?[0-9]+");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logs messages to log file.
|
/// Logs messages to log file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1193,9 +1218,19 @@ namespace SekiroFpsUnlockAndMore
|
||||||
else e.CancelCommand();
|
else e.CancelCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CbSelectFov_DropDownClosed(object sender, EventArgs e)
|
private void SignedNumeric_PreviewTextInput(object sender, TextCompositionEventArgs e)
|
||||||
{
|
{
|
||||||
if (this.cbFov.IsChecked == true) PatchFov();
|
e.Handled = IsSignedNumericInput(e.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SignedNumeric_PastingHandler(object sender, DataObjectPastingEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.DataObject.GetDataPresent(typeof(string)))
|
||||||
|
{
|
||||||
|
string text = (string)e.DataObject.GetData(typeof(string));
|
||||||
|
if (IsSignedNumericInput(text)) e.CancelCommand();
|
||||||
|
}
|
||||||
|
else e.CancelCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CbFramelock_Check_Handler(object sender, RoutedEventArgs e)
|
private void CbFramelock_Check_Handler(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -1213,14 +1248,40 @@ namespace SekiroFpsUnlockAndMore
|
||||||
PatchFov();
|
PatchFov();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BFov0_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.tbFov.Text = "0";
|
||||||
|
if (this.cbFov.IsChecked == true) PatchFov();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BFovLower_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Int32.TryParse(this.tbFov.Text, out int fov) && fov > -91)
|
||||||
|
{
|
||||||
|
this.tbFov.Text = (fov - 5).ToString();
|
||||||
|
if (this.cbFov.IsChecked == true) PatchFov();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BFovHigher_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Int32.TryParse(this.tbFov.Text, out int fov) && fov < 91)
|
||||||
|
{
|
||||||
|
this.tbFov.Text = (fov + 5).ToString();
|
||||||
|
if (this.cbFov.IsChecked == true) PatchFov();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CbBorderless_Checked(object sender, RoutedEventArgs e)
|
private void CbBorderless_Checked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!this.cbBorderless.IsEnabled) return;
|
||||||
this.cbBorderlessStretch.IsEnabled = true;
|
this.cbBorderlessStretch.IsEnabled = true;
|
||||||
PatchWindow();
|
PatchWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CbBorderless_Unchecked(object sender, RoutedEventArgs e)
|
private void CbBorderless_Unchecked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!this.cbBorderless.IsEnabled) return;
|
||||||
this.cbBorderlessStretch.IsEnabled = false;
|
this.cbBorderlessStretch.IsEnabled = false;
|
||||||
this.cbBorderlessStretch.IsChecked = false;
|
this.cbBorderlessStretch.IsChecked = false;
|
||||||
PatchWindow();
|
PatchWindow();
|
||||||
|
|
@ -1228,6 +1289,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
private void CbBorderlessStretch_Check_Handler(object sender, RoutedEventArgs e)
|
private void CbBorderlessStretch_Check_Handler(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!this.cbBorderlessStretch.IsEnabled) return;
|
||||||
PatchWindow();
|
PatchWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1255,9 +1317,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
private void BGsLower_Click(object sender, RoutedEventArgs e)
|
private void BGsLower_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
int gameSpeed = -1;
|
if (Int32.TryParse(this.tbGameSpeed.Text, out int gameSpeed) && gameSpeed > 4)
|
||||||
Int32.TryParse(this.tbGameSpeed.Text, out gameSpeed);
|
|
||||||
if (gameSpeed > -1 && gameSpeed > 4)
|
|
||||||
{
|
{
|
||||||
this.tbGameSpeed.Text = (gameSpeed - 5).ToString();
|
this.tbGameSpeed.Text = (gameSpeed - 5).ToString();
|
||||||
if (cbGameSpeed.IsChecked == true) PatchGameSpeed();
|
if (cbGameSpeed.IsChecked == true) PatchGameSpeed();
|
||||||
|
|
@ -1266,9 +1326,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
private void BGsHigher_Click(object sender, RoutedEventArgs e)
|
private void BGsHigher_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
int gameSpeed = -1;
|
if (Int32.TryParse(this.tbGameSpeed.Text, out int gameSpeed) && gameSpeed < 995)
|
||||||
Int32.TryParse(this.tbGameSpeed.Text, out gameSpeed);
|
|
||||||
if (gameSpeed > -1 && gameSpeed < 995)
|
|
||||||
{
|
{
|
||||||
this.tbGameSpeed.Text = (gameSpeed + 5).ToString();
|
this.tbGameSpeed.Text = (gameSpeed + 5).ToString();
|
||||||
if (cbGameSpeed.IsChecked == true) PatchGameSpeed();
|
if (cbGameSpeed.IsChecked == true) PatchGameSpeed();
|
||||||
|
|
@ -1294,9 +1352,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
private void BPsLower_Click(object sender, RoutedEventArgs e)
|
private void BPsLower_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
int playerSpeed = -1;
|
if (Int32.TryParse(this.tbPlayerSpeed.Text, out int playerSpeed) && playerSpeed > 4)
|
||||||
Int32.TryParse(this.tbPlayerSpeed.Text, out playerSpeed);
|
|
||||||
if (playerSpeed > -1 && playerSpeed > 4)
|
|
||||||
{
|
{
|
||||||
this.tbPlayerSpeed.Text = (playerSpeed - 5).ToString();
|
this.tbPlayerSpeed.Text = (playerSpeed - 5).ToString();
|
||||||
if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed();
|
if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed();
|
||||||
|
|
@ -1305,9 +1361,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
|
|
||||||
private void BPsHigher_Click(object sender, RoutedEventArgs e)
|
private void BPsHigher_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
int playerSpeed = -1;
|
if (Int32.TryParse(this.tbPlayerSpeed.Text, out int playerSpeed) && playerSpeed < 995)
|
||||||
Int32.TryParse(this.tbPlayerSpeed.Text, out playerSpeed);
|
|
||||||
if (playerSpeed > -1 && playerSpeed < 995)
|
|
||||||
{
|
{
|
||||||
this.tbPlayerSpeed.Text = (playerSpeed + 5).ToString();
|
this.tbPlayerSpeed.Text = (playerSpeed + 5).ToString();
|
||||||
if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed();
|
if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed();
|
||||||
|
|
|
||||||
|
|
@ -5,51 +5,188 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace SekiroFpsUnlockAndMore
|
namespace SekiroFpsUnlockAndMore
|
||||||
{
|
{
|
||||||
class CodeCaveGenerator
|
internal enum PointerStyle
|
||||||
{
|
{
|
||||||
private class CodeCave
|
dwRelative,
|
||||||
|
dwAbsolute,
|
||||||
|
qwRelative,
|
||||||
|
qwAbsolute
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class PointerStyleMethods
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns pointer size of pointer style.
|
||||||
|
/// </summary>
|
||||||
|
public static int PointerSize(this PointerStyle pointerStyle)
|
||||||
|
{
|
||||||
|
if (pointerStyle == PointerStyle.qwAbsolute || pointerStyle == PointerStyle.qwRelative) return 8;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemoryCaveGenerator
|
||||||
|
{
|
||||||
|
private class MemoryCave
|
||||||
{
|
{
|
||||||
internal readonly long InstructionAddress;
|
internal readonly long InstructionAddress;
|
||||||
internal readonly int OverwriteLength;
|
internal readonly long CaveAddress;
|
||||||
internal readonly long CodeCaveAddress;
|
|
||||||
internal bool Active;
|
internal bool Active;
|
||||||
private byte[] _originalInstructionset;
|
private byte[] _originalInstruction;
|
||||||
internal byte[] OriginalInstructionset
|
internal byte[] OriginalInstruction
|
||||||
{
|
{
|
||||||
get => _originalInstructionset;
|
get => _originalInstruction;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_originalInstructionset == null)
|
if (_originalInstruction == null)
|
||||||
_originalInstructionset = value;
|
_originalInstruction = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal CodeCave(long instructionAddress, int overwriteLength, long codeCaveAddress)
|
internal MemoryCave(long instructionAddress, long caveAddress)
|
||||||
{
|
{
|
||||||
InstructionAddress = instructionAddress;
|
InstructionAddress = instructionAddress;
|
||||||
OverwriteLength = overwriteLength;
|
CaveAddress = caveAddress;
|
||||||
CodeCaveAddress = codeCaveAddress;
|
_originalInstruction = null;
|
||||||
Active = false;
|
Active = false;
|
||||||
_originalInstructionset = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DataCave : MemoryCave
|
||||||
|
{
|
||||||
|
internal readonly PointerStyle PointerStyle;
|
||||||
|
|
||||||
|
internal DataCave(long instructionAddress, long codeCaveAddress, PointerStyle pointerStyle) : base(instructionAddress, codeCaveAddress)
|
||||||
|
{
|
||||||
|
PointerStyle = pointerStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CodeCave : MemoryCave
|
||||||
|
{
|
||||||
|
internal readonly int OverwriteLength;
|
||||||
|
|
||||||
|
internal CodeCave(long instructionAddress, long codeCaveAddress, int overwriteLength) : base(instructionAddress, codeCaveAddress)
|
||||||
|
{
|
||||||
|
OverwriteLength = overwriteLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, DataCave> _dataCaves;
|
||||||
private Dictionary<string, CodeCave> _codeCaves;
|
private Dictionary<string, CodeCave> _codeCaves;
|
||||||
private static IntPtr _hProcess;
|
private static IntPtr _hProcess;
|
||||||
private static long _lpBaseAddress;
|
private static long _lpBaseAddress;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize functionality to create and manage code caves in given process's memory.
|
/// Initialize functionality to create and manage memory caves in given process's memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hProcess">The handle to the process, needs all access flag.</param>
|
/// <param name="hProcess">The handle to the process, needs all access flag.</param>
|
||||||
/// <param name="lpBaseAddress">The base address of the process.</param>
|
/// <param name="lpBaseAddress">The base address of the process.</param>
|
||||||
internal CodeCaveGenerator(IntPtr hProcess, long lpBaseAddress)
|
internal MemoryCaveGenerator(IntPtr hProcess, long lpBaseAddress)
|
||||||
{
|
{
|
||||||
|
_dataCaves = new Dictionary<string, DataCave>();
|
||||||
_codeCaves = new Dictionary<string, CodeCave>();
|
_codeCaves = new Dictionary<string, CodeCave>();
|
||||||
_hProcess = hProcess;
|
_hProcess = hProcess;
|
||||||
_lpBaseAddress = lpBaseAddress;
|
_lpBaseAddress = lpBaseAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new data cave with a unique name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szCaveName">The unique name of the data cave. Used to enable and disable caves.</param>
|
||||||
|
/// <param name="lpPointerAddress">The address of the pointer that should later access the data in the cave.</param>
|
||||||
|
/// <param name="cbDataInsert">The data to place inside the data cave.</param>
|
||||||
|
/// <param name="pointerStyle">The type of the pointer to later replace with data cave address, default assumes a 4 byte relative pointer.</param>
|
||||||
|
/// <returns>True if code cave has been successfully created and is ready to be activated, false otherwise.</returns>
|
||||||
|
internal bool CreateNewDataCave(string szCaveName, long lpPointerAddress, byte[] cbDataInsert, PointerStyle pointerStyle = PointerStyle.dwRelative)
|
||||||
|
{
|
||||||
|
if (_dataCaves.ContainsKey(szCaveName))
|
||||||
|
_dataCaves.Remove(szCaveName);
|
||||||
|
long caveAddress = CreateDataCaveForPointer(_hProcess, _lpBaseAddress, lpPointerAddress, pointerStyle.PointerSize(), cbDataInsert);
|
||||||
|
if (caveAddress < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// read original pointer
|
||||||
|
byte[] cbOriginalPointer = new byte[pointerStyle.PointerSize()];
|
||||||
|
if (!ReadProcessMemory(_hProcess, lpPointerAddress, cbOriginalPointer, (ulong)pointerStyle.PointerSize(), out IntPtr lpNumberOfBytesRead) || lpNumberOfBytesRead.ToInt32() != pointerStyle.PointerSize())
|
||||||
|
{
|
||||||
|
MainWindow.LogToFile("Failed to read original pointer in MemoryCaveGenerator()!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_dataCaves.Add(szCaveName, new DataCave(lpPointerAddress, caveAddress, pointerStyle));
|
||||||
|
_dataCaves[szCaveName].OriginalInstruction = cbOriginalPointer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Activates a data cave by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szCaveName">The unique name of the data cave.</param>
|
||||||
|
/// <returns>True if data cave could be activated.</returns>
|
||||||
|
internal bool ActivateDataCaveByName(string szCaveName)
|
||||||
|
{
|
||||||
|
if (!_dataCaves.ContainsKey(szCaveName) || _dataCaves[szCaveName].Active)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// get pointer value
|
||||||
|
byte[] cbPointer = new byte[_dataCaves[szCaveName].PointerStyle.PointerSize()];
|
||||||
|
if (_dataCaves[szCaveName].PointerStyle == PointerStyle.dwAbsolute || _dataCaves[szCaveName].PointerStyle == PointerStyle.qwAbsolute)
|
||||||
|
cbPointer = _dataCaves[szCaveName].PointerStyle.PointerSize() == 4 ? BitConverter.GetBytes((int)_dataCaves[szCaveName].CaveAddress) : BitConverter.GetBytes(_dataCaves[szCaveName].CaveAddress);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long lpRip = _dataCaves[szCaveName].InstructionAddress + _dataCaves[szCaveName].PointerStyle.PointerSize();
|
||||||
|
cbPointer = _dataCaves[szCaveName].PointerStyle.PointerSize() == 4 ? BitConverter.GetBytes((int)(_dataCaves[szCaveName].CaveAddress - lpRip)) : BitConverter.GetBytes(_dataCaves[szCaveName].CaveAddress - lpRip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite pointer with new data cave address
|
||||||
|
if (!WriteProcessMemory(_hProcess, _dataCaves[szCaveName].InstructionAddress, cbPointer, (ulong)cbPointer.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != _dataCaves[szCaveName].PointerStyle.PointerSize())
|
||||||
|
{
|
||||||
|
MainWindow.LogToFile("Failed to overwrite target pointer in MemoryCaveGenerator()!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dataCaves[szCaveName].Active = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deactivates a data cave by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szCaveName">The unique name of the data cave.</param>
|
||||||
|
/// <returns>True if data cave could be deactivated.</returns>
|
||||||
|
internal bool DeactivateDataCaveByName(string szCaveName)
|
||||||
|
{
|
||||||
|
if (!_dataCaves.ContainsKey(szCaveName) || !_dataCaves[szCaveName].Active || _dataCaves[szCaveName].InstructionAddress < 0 || _dataCaves[szCaveName].OriginalInstruction == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!WriteProcessMemory(_hProcess, _dataCaves[szCaveName].InstructionAddress, _dataCaves[szCaveName].OriginalInstruction, (ulong)_dataCaves[szCaveName].OriginalInstruction.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != _dataCaves[szCaveName].PointerStyle.PointerSize())
|
||||||
|
{
|
||||||
|
MainWindow.LogToFile("Could not disable data cave in MemoryCaveGenerator()!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_dataCaves[szCaveName].Active = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the data inside the data cave by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szCaveName">The unique name of the data cave.</param>
|
||||||
|
/// <param name="cbNewData">The new data to write.</param>
|
||||||
|
/// <returns>True if data could be written.</returns>
|
||||||
|
internal bool UpdateDataCaveValueByName(string szCaveName, byte[] cbNewData)
|
||||||
|
{
|
||||||
|
if (!_dataCaves.ContainsKey(szCaveName) || _dataCaves[szCaveName].CaveAddress < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!WriteProcessMemory(_hProcess, _dataCaves[szCaveName].CaveAddress, cbNewData, (ulong)cbNewData.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != cbNewData.Length)
|
||||||
|
{
|
||||||
|
MainWindow.LogToFile("Could not write data to cave in MemoryCaveGenerator()!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new code cave with a unique name.
|
/// Creates a new code cave with a unique name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -69,7 +206,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
long caveAddress = CreateCodeCaveForInstruction(_hProcess, _lpBaseAddress, lpInstructionAddress, dwOverwriteLength, cbCodeInject, bCopyOverwrittenInstructions);
|
long caveAddress = CreateCodeCaveForInstruction(_hProcess, _lpBaseAddress, lpInstructionAddress, dwOverwriteLength, cbCodeInject, bCopyOverwrittenInstructions);
|
||||||
if (caveAddress < 0)
|
if (caveAddress < 0)
|
||||||
return false;
|
return false;
|
||||||
_codeCaves.Add(szCaveName, new CodeCave(lpInstructionAddress, dwOverwriteLength, caveAddress));
|
_codeCaves.Add(szCaveName, new CodeCave(lpInstructionAddress, caveAddress, dwOverwriteLength));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,10 +220,10 @@ namespace SekiroFpsUnlockAndMore
|
||||||
if (!_codeCaves.ContainsKey(szCaveName) || _codeCaves[szCaveName].Active)
|
if (!_codeCaves.ContainsKey(szCaveName) || _codeCaves[szCaveName].Active)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
byte[] originalInstructionset = ActivateCodeCaveForInstruction(_hProcess, _codeCaves[szCaveName].InstructionAddress, _codeCaves[szCaveName].OverwriteLength, _codeCaves[szCaveName].CodeCaveAddress);
|
byte[] originalInstructionset = ActivateCodeCaveForInstruction(_hProcess, _codeCaves[szCaveName].InstructionAddress, _codeCaves[szCaveName].OverwriteLength, _codeCaves[szCaveName].CaveAddress);
|
||||||
if (originalInstructionset.Length != _codeCaves[szCaveName].OverwriteLength)
|
if (originalInstructionset.Length != _codeCaves[szCaveName].OverwriteLength)
|
||||||
return false;
|
return false;
|
||||||
_codeCaves[szCaveName].OriginalInstructionset = originalInstructionset;
|
_codeCaves[szCaveName].OriginalInstruction = originalInstructionset;
|
||||||
_codeCaves[szCaveName].Active = true;
|
_codeCaves[szCaveName].Active = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -98,18 +235,42 @@ namespace SekiroFpsUnlockAndMore
|
||||||
/// <returns>True if code cave could be deactivated.</returns>
|
/// <returns>True if code cave could be deactivated.</returns>
|
||||||
internal bool DeactivateCodeCaveByName(string szCaveName)
|
internal bool DeactivateCodeCaveByName(string szCaveName)
|
||||||
{
|
{
|
||||||
if (!_codeCaves.ContainsKey(szCaveName) || !_codeCaves[szCaveName].Active || _codeCaves[szCaveName].InstructionAddress < 0 || _codeCaves[szCaveName].OriginalInstructionset == null)
|
if (!_codeCaves.ContainsKey(szCaveName) || !_codeCaves[szCaveName].Active || _codeCaves[szCaveName].InstructionAddress < 0 || _codeCaves[szCaveName].OriginalInstruction == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!WriteProcessMemory(_hProcess, _codeCaves[szCaveName].InstructionAddress, _codeCaves[szCaveName].OriginalInstructionset, (ulong) _codeCaves[szCaveName].OriginalInstructionset.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != _codeCaves[szCaveName].OriginalInstructionset.Length)
|
if (!WriteProcessMemory(_hProcess, _codeCaves[szCaveName].InstructionAddress, _codeCaves[szCaveName].OriginalInstruction, (ulong)_codeCaves[szCaveName].OriginalInstruction.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != _codeCaves[szCaveName].OriginalInstruction.Length)
|
||||||
{
|
{
|
||||||
MainWindow.LogToFile("Could not disable code cave in CodeCaveGenerator()!");
|
MainWindow.LogToFile("Could not disable code cave in MemoryCaveGenerator()!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_codeCaves[szCaveName].Active = false;
|
_codeCaves[szCaveName].Active = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data cave address of an already created cave by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szCaveName">The unique name of the data cave.</param>
|
||||||
|
/// <returns>The address of the code cave, -1 if none found.</returns>
|
||||||
|
internal long GetDataCaveAddressByName(string szCaveName)
|
||||||
|
{
|
||||||
|
if (!_dataCaves.ContainsKey(szCaveName) || _dataCaves[szCaveName].CaveAddress == 0)
|
||||||
|
return -1;
|
||||||
|
return _dataCaves[szCaveName].CaveAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data cave original pointer value by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szCaveName">The unique name of the data cave.</param>
|
||||||
|
/// <returns>The original pointer value of the data cave, null if none found.</returns>
|
||||||
|
internal byte[] GetDataCaveOriginalPointerByName(string szCaveName)
|
||||||
|
{
|
||||||
|
if (!_dataCaves.ContainsKey(szCaveName) || _dataCaves[szCaveName].OriginalInstruction == null)
|
||||||
|
return null;
|
||||||
|
return _dataCaves[szCaveName].OriginalInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the code cave address of an already created cave by name.
|
/// Gets the code cave address of an already created cave by name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -117,19 +278,50 @@ namespace SekiroFpsUnlockAndMore
|
||||||
/// <returns>The address of the code cave, -1 if none found.</returns>
|
/// <returns>The address of the code cave, -1 if none found.</returns>
|
||||||
internal long GetCodeCaveAddressByName(string szCaveName)
|
internal long GetCodeCaveAddressByName(string szCaveName)
|
||||||
{
|
{
|
||||||
if (!_codeCaves.ContainsKey(szCaveName) || _codeCaves[szCaveName].CodeCaveAddress == 0)
|
if (!_codeCaves.ContainsKey(szCaveName) || _codeCaves[szCaveName].CaveAddress == 0)
|
||||||
return -1;
|
return -1;
|
||||||
return _codeCaves[szCaveName].CodeCaveAddress;
|
return _codeCaves[szCaveName].CaveAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears all saved code caves. Does not deactivate them.
|
/// Clears all saved caves internally. Does not deactivate nor remove them from memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void ClearCodeCaves()
|
internal void ClearCaves()
|
||||||
{
|
{
|
||||||
|
_dataCaves.Clear();
|
||||||
_codeCaves.Clear();
|
_codeCaves.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a data cave to link a pointer to within given process's memory in reach of given instruction address.
|
||||||
|
/// <para>Does not activate the data cave yet.</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hProcess">The handle to the process, needs all access flag.</param>
|
||||||
|
/// <param name="lpBaseAddress">The base address of the process.</param>
|
||||||
|
/// <param name="lpPointerAddress">The address of the pointer that should later access the data in the cave.</param>
|
||||||
|
/// <param name="dwPointerLength">The lengths of the pointer to later replace with data cave address.</param>
|
||||||
|
/// <param name="cbDataInsert">The data to place inside the data cave.</param>
|
||||||
|
/// <remarks>Assumes a relative 4 bytes pointer, will fail if there is no free memory within signed integer range (4bytes) from lpInstructionAddress.</remarks>
|
||||||
|
/// <returns>The address of the beginning of the data cave, -1 if operation failed.</returns>
|
||||||
|
private static long CreateDataCaveForPointer(IntPtr hProcess, long lpBaseAddress, long lpPointerAddress, int dwPointerLength, byte[] cbDataInsert)
|
||||||
|
{
|
||||||
|
if (IntPtr.Size != 8)
|
||||||
|
throw new Exception("Only x64 is supported!");
|
||||||
|
|
||||||
|
long lpAllocationAddress = AllocateMemoryNearAddress(hProcess, lpBaseAddress, lpPointerAddress, cbDataInsert.Length, false, dwPointerLength);
|
||||||
|
if (lpAllocationAddress < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// fill data cave
|
||||||
|
if (!WriteProcessMemory(hProcess, lpAllocationAddress, cbDataInsert, (ulong)cbDataInsert.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != cbDataInsert.Length)
|
||||||
|
{
|
||||||
|
MainWindow.LogToFile("Failed to fill data cave in MemoryCaveGenerator()!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpAllocationAddress;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a code cave to inject code within given process's memory in reach of given instruction address.
|
/// Creates a code cave to inject code within given process's memory in reach of given instruction address.
|
||||||
/// <para>Does not activate the code cave yet.</para>
|
/// <para>Does not activate the code cave yet.</para>
|
||||||
|
|
@ -154,45 +346,13 @@ namespace SekiroFpsUnlockAndMore
|
||||||
byte[] cbOriginalInstructionset = new byte[dwOverwriteLength];
|
byte[] cbOriginalInstructionset = new byte[dwOverwriteLength];
|
||||||
if (!ReadProcessMemory(hProcess, lpInstructionAddress, cbOriginalInstructionset, (ulong)dwOverwriteLength, out IntPtr lpNumberOfBytesRead) || lpNumberOfBytesRead.ToInt32() != dwOverwriteLength)
|
if (!ReadProcessMemory(hProcess, lpInstructionAddress, cbOriginalInstructionset, (ulong)dwOverwriteLength, out IntPtr lpNumberOfBytesRead) || lpNumberOfBytesRead.ToInt32() != dwOverwriteLength)
|
||||||
{
|
{
|
||||||
MainWindow.LogToFile("Failed to read original instruction set in CodeCaveGenerator()!");
|
MainWindow.LogToFile("Failed to read original instruction set in MemoryCaveGenerator()!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSTEM_INFO si = new SYSTEM_INFO();
|
long lpAllocationAddress = AllocateMemoryNearAddress(hProcess, lpBaseAddress, lpInstructionAddress, cbCodeInject.Length + dwOverwriteLength, true, 6);
|
||||||
GetSystemInfo(out si);
|
if (lpAllocationAddress < 1)
|
||||||
|
|
||||||
// find lowest and highest possible address in jump range from lpInstructionAddress
|
|
||||||
int iMinimalCaveSize = 8 * (int)Math.Round((cbCodeInject.Length + dwOverwriteLength + 6) / 8.0); // nearest size rounded to 8 bytes
|
|
||||||
if (iMinimalCaveSize < 32) iMinimalCaveSize = 32;
|
|
||||||
long lpMinimalJmpAddress = lpInstructionAddress + 6 - 0x70000000; // Int32.MinValue + a little buffer overhead
|
|
||||||
long lpMaximumJmpAddress = lpInstructionAddress + 0x70000000 - iMinimalCaveSize; // Int32.MaxValue + a little buffer overhead
|
|
||||||
if (lpMinimalJmpAddress < si.lpMinimumApplicationAddress) lpMinimalJmpAddress = si.lpMinimumApplicationAddress;
|
|
||||||
if (lpMaximumJmpAddress > si.lpMaximumApplicationAddress - iMinimalCaveSize) lpMaximumJmpAddress = si.lpMaximumApplicationAddress - iMinimalCaveSize;
|
|
||||||
|
|
||||||
// determine lowest possible memory block we could allocate for cave assuming base address lies at the beginning of a memory block
|
|
||||||
long lpPreferredAddress = lpBaseAddress - (int)((lpBaseAddress - lpMinimalJmpAddress) / si.dwAllocationGranularity) * si.dwAllocationGranularity;
|
|
||||||
|
|
||||||
// find lowest useable memory block and allocate it
|
|
||||||
long lpAllocationAddress = 0;
|
|
||||||
MEMORY_BASIC_INFORMATION64 mbi = new MEMORY_BASIC_INFORMATION64();
|
|
||||||
while (lpPreferredAddress < lpMaximumJmpAddress)
|
|
||||||
{
|
|
||||||
if (VirtualQueryEx(hProcess, new IntPtr(lpPreferredAddress), out mbi, MEMORY_BASIC_INFORMATION64_LENGTH) != MEMORY_BASIC_INFORMATION64_LENGTH)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (mbi.State == MEM_FREE && mbi.RegionSize > (ulong)iMinimalCaveSize)
|
|
||||||
{
|
|
||||||
lpAllocationAddress = VirtualAllocEx(hProcess, new IntPtr((long)mbi.BaseAddress), (uint)iMinimalCaveSize, ALLOCATIONTYPE_RESERVE | ALLOCATIONTYPE_COMMIT, MEMORYPROTECTION_EXECUTEREADWRITE);
|
|
||||||
if (lpAllocationAddress > 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
lpPreferredAddress = (long)mbi.BaseAddress + si.dwAllocationGranularity;
|
|
||||||
}
|
|
||||||
if (lpAllocationAddress == 0)
|
|
||||||
{
|
|
||||||
MainWindow.LogToFile("No usable memory region found or failed to allocate memory for code cave in CodeCaveGenerator()!");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
// calculate jump from cave to back to where we came from
|
// calculate jump from cave to back to where we came from
|
||||||
uint lpRelativePointerFromCave = (uint)((lpInstructionAddress + dwOverwriteLength) - (lpAllocationAddress + cbCodeInject.Length + (bCopyOverwrittenInstructions ? dwOverwriteLength : 0))) - 5;
|
uint lpRelativePointerFromCave = (uint)((lpInstructionAddress + dwOverwriteLength) - (lpAllocationAddress + cbCodeInject.Length + (bCopyOverwrittenInstructions ? dwOverwriteLength : 0))) - 5;
|
||||||
|
|
@ -210,7 +370,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
// fill code cave with instructions
|
// fill code cave with instructions
|
||||||
if (!WriteProcessMemory(hProcess, lpAllocationAddress, cbCaveInstructions, (ulong)cbCaveInstructions.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != cbCaveInstructions.Length)
|
if (!WriteProcessMemory(hProcess, lpAllocationAddress, cbCaveInstructions, (ulong)cbCaveInstructions.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != cbCaveInstructions.Length)
|
||||||
{
|
{
|
||||||
MainWindow.LogToFile("Failed to fill code cave in CodeCaveGenerator()!");
|
MainWindow.LogToFile("Failed to fill code cave in MemoryCaveGenerator()!");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,7 +392,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
byte[] cbOriginalInstructionset = new byte[dwOverwriteLength];
|
byte[] cbOriginalInstructionset = new byte[dwOverwriteLength];
|
||||||
if (!ReadProcessMemory(hProcess, lpInstructionAddress, cbOriginalInstructionset, (ulong)dwOverwriteLength, out IntPtr lpNumberOfBytesRead) || lpNumberOfBytesRead.ToInt32() != dwOverwriteLength)
|
if (!ReadProcessMemory(hProcess, lpInstructionAddress, cbOriginalInstructionset, (ulong)dwOverwriteLength, out IntPtr lpNumberOfBytesRead) || lpNumberOfBytesRead.ToInt32() != dwOverwriteLength)
|
||||||
{
|
{
|
||||||
MainWindow.LogToFile("Failed to read original instruction set in CodeCaveGenerator()!");
|
MainWindow.LogToFile("Failed to read original instruction set in MemoryCaveGenerator()!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,17 +413,69 @@ namespace SekiroFpsUnlockAndMore
|
||||||
// write jump instruction to target address
|
// write jump instruction to target address
|
||||||
if (!WriteProcessMemory(hProcess, lpInstructionAddress, cbJumpToCaveInstruction, (ulong)cbJumpToCaveInstruction.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != cbJumpToCaveInstruction.Length)
|
if (!WriteProcessMemory(hProcess, lpInstructionAddress, cbJumpToCaveInstruction, (ulong)cbJumpToCaveInstruction.Length, out IntPtr lpNumberOfBytesWritten) || lpNumberOfBytesWritten.ToInt32() != cbJumpToCaveInstruction.Length)
|
||||||
{
|
{
|
||||||
MainWindow.LogToFile("Failed to overwrite target instructions in CodeCaveGenerator()!");
|
MainWindow.LogToFile("Failed to overwrite target instructions in MemoryCaveGenerator()!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cbOriginalInstructionset;
|
return cbOriginalInstructionset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates memory at least the size of given sizes in DWORD range of given instruction address.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hProcess">The handle to the process, needs all access flag.</param>
|
||||||
|
/// <param name="lpBaseAddress">The base address of the process.</param>
|
||||||
|
/// <param name="lpInstructionAddress">The address of the instruction that should later access the allocated memory.</param>
|
||||||
|
/// <param name="dwInsertLength">The length of the insert that should be placed in allocated memory.</param>
|
||||||
|
/// <param name="bExecuteAccess">A boolean to determine if allocated memory should be executable, default is true.</param>
|
||||||
|
/// <param name="dwAccessInstructionLength">The length of the instruction that will jump or read from the allocated memory. Default assumes a 5 bytes JMP.</param>
|
||||||
|
/// <returns>The address of the beginning of the memory allocated, -1 if operation failed.</returns>
|
||||||
|
private static long AllocateMemoryNearAddress(IntPtr hProcess, long lpBaseAddress, long lpInstructionAddress, int dwInsertLength, bool bExecuteAccess = true, int dwAccessInstructionLength = 6)
|
||||||
|
{
|
||||||
|
SYSTEM_INFO si = new SYSTEM_INFO();
|
||||||
|
GetSystemInfo(out si);
|
||||||
|
|
||||||
|
// find lowest and highest possible address in jump range from lpInstructionAddress
|
||||||
|
int iMinimalCaveSize = 8 * (int)Math.Round((dwInsertLength + dwAccessInstructionLength) / 8.0); // nearest size rounded to 8 bytes
|
||||||
|
if (iMinimalCaveSize < 32) iMinimalCaveSize = 32;
|
||||||
|
long lpMinimalJmpAddress = lpInstructionAddress + dwAccessInstructionLength - 0x70000000; // Int32.MinValue + a little buffer overhead
|
||||||
|
long lpMaximumJmpAddress = lpInstructionAddress + 0x70000000 - iMinimalCaveSize; // Int32.MaxValue + a little buffer overhead
|
||||||
|
if (lpMinimalJmpAddress < si.lpMinimumApplicationAddress) lpMinimalJmpAddress = si.lpMinimumApplicationAddress;
|
||||||
|
if (lpMaximumJmpAddress > si.lpMaximumApplicationAddress - iMinimalCaveSize) lpMaximumJmpAddress = si.lpMaximumApplicationAddress - iMinimalCaveSize;
|
||||||
|
|
||||||
|
// determine lowest possible memory block we could allocate for cave assuming base address lies at the beginning of a memory block
|
||||||
|
long lpPreferredAddress = lpBaseAddress - (int)((lpBaseAddress - lpMinimalJmpAddress) / si.dwAllocationGranularity) * si.dwAllocationGranularity;
|
||||||
|
|
||||||
|
// find lowest useable memory block and allocate it
|
||||||
|
long lpAllocationAddress = 0;
|
||||||
|
MEMORY_BASIC_INFORMATION64 mbi = new MEMORY_BASIC_INFORMATION64();
|
||||||
|
while (lpPreferredAddress < lpMaximumJmpAddress)
|
||||||
|
{
|
||||||
|
if (VirtualQueryEx(hProcess, new IntPtr(lpPreferredAddress), out mbi, MEMORY_BASIC_INFORMATION64_LENGTH) != MEMORY_BASIC_INFORMATION64_LENGTH)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (mbi.State == MEM_FREE && mbi.RegionSize > (ulong)iMinimalCaveSize)
|
||||||
|
{
|
||||||
|
lpAllocationAddress = VirtualAllocEx(hProcess, new IntPtr((long)mbi.BaseAddress), (uint)iMinimalCaveSize, ALLOCATIONTYPE_RESERVE | ALLOCATIONTYPE_COMMIT, bExecuteAccess ? MEMORYPROTECTION_EXECUTEREADWRITE : MEMORYPROTECTION_READWRITE);
|
||||||
|
if (lpAllocationAddress > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lpPreferredAddress = (long)mbi.BaseAddress + si.dwAllocationGranularity;
|
||||||
|
}
|
||||||
|
if (lpAllocationAddress == 0)
|
||||||
|
{
|
||||||
|
MainWindow.LogToFile("No usable memory region found or failed to allocate memory for code cave in MemoryCaveGenerator()!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpAllocationAddress;
|
||||||
|
}
|
||||||
|
|
||||||
#region WINAPI
|
#region WINAPI
|
||||||
|
|
||||||
private const uint ALLOCATIONTYPE_COMMIT = 0x1000;
|
private const uint ALLOCATIONTYPE_COMMIT = 0x1000;
|
||||||
private const uint ALLOCATIONTYPE_RESERVE = 0x2000;
|
private const uint ALLOCATIONTYPE_RESERVE = 0x2000;
|
||||||
|
private const uint MEMORYPROTECTION_READWRITE = 0x04;
|
||||||
private const uint MEMORYPROTECTION_EXECUTEREADWRITE = 0x40;
|
private const uint MEMORYPROTECTION_EXECUTEREADWRITE = 0x40;
|
||||||
private const int MEMORY_BASIC_INFORMATION64_LENGTH = 48;
|
private const int MEMORY_BASIC_INFORMATION64_LENGTH = 48;
|
||||||
private const int MEM_FREE = 0x10000;
|
private const int MEM_FREE = 0x10000;
|
||||||
|
|
@ -21,5 +21,5 @@ using System.Runtime.InteropServices;
|
||||||
ResourceDictionaryLocation.SourceAssembly
|
ResourceDictionaryLocation.SourceAssembly
|
||||||
)]
|
)]
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.2.1.1")]
|
[assembly: AssemblyVersion("1.2.2.0")]
|
||||||
[assembly: AssemblyFileVersion("1.2.1.1")]
|
[assembly: AssemblyFileVersion("1.2.2.0")]
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</ApplicationDefinition>
|
</ApplicationDefinition>
|
||||||
<Compile Include="CodeCaveGenerator.cs" />
|
<Compile Include="MemoryCaveGenerator.cs" />
|
||||||
<Compile Include="SettingsService.cs" />
|
<Compile Include="SettingsService.cs" />
|
||||||
<Compile Include="StatusViewModel.cs" />
|
<Compile Include="StatusViewModel.cs" />
|
||||||
<Page Include="MainWindow.xaml">
|
<Page Include="MainWindow.xaml">
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace SekiroFpsUnlockAndMore
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
public bool cbFov { get; set; }
|
public bool cbFov { get; set; }
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
public int cbSelectFov { get; set; }
|
public int tbFov { get; set; }
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
public bool cbBorderless { get; set; }
|
public bool cbBorderless { get; set; }
|
||||||
[XmlElement]
|
[XmlElement]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue