Skip to content

Commit

Permalink
fix: memory access checking
Browse files Browse the repository at this point in the history
  • Loading branch information
ewrogers committed May 19, 2023
1 parent f18cb36 commit 7223797
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 31 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this library will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.5.4] - 2023-05-19

### Fixed

- Skill cooldown memory reading inconsistencies

## [4.5.3] - 2023-05-18

### Fixed
Expand Down
11 changes: 7 additions & 4 deletions SleepHunter/IO/Process/ProcessMemoryScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ namespace SleepHunter.IO.Process
{
internal sealed class ProcessMemoryScanner : IDisposable
{
static readonly uint MinimumVmAddress = 0x0040_0000;
static readonly uint MaximumVmAddress = 0xFFFF_FFFF;
const int DefaultPageSize = 0x1000;
const uint MinimumVmAddress = 0x0040_0000;
const uint MaximumVmAddress = 0xFFFF_FFFF;

bool isDisposed;
IntPtr processHandle;
Expand All @@ -36,6 +37,9 @@ public ProcessMemoryScanner(IntPtr processHandle, bool leaveOpen = false)
NativeMethods.GetNativeSystemInfo(out var sysInfo);
pageSize = (int)sysInfo.PageSize;

if (pageSize <= 0)
pageSize = DefaultPageSize;

searchBuffer = new byte[pageSize];
}

Expand Down Expand Up @@ -174,8 +178,7 @@ public IEnumerable<IntPtr> FindAll(byte[] bytes, int size, long startingAddress

for (int i = 0; i < numberOfPages; i++)
{
int numberOfBytesRead;
var result = NativeMethods.ReadProcessMemory(processHandle, memoryInfo.BaseAddress + (i * pageSize), searchBuffer, searchBuffer.Length, out numberOfBytesRead);
var result = NativeMethods.ReadProcessMemory(processHandle, memoryInfo.BaseAddress + (i * pageSize), searchBuffer, searchBuffer.Length, out var numberOfBytesRead);

if (!result || numberOfBytesRead != searchBuffer.Length)
throw new Win32Exception("Unable to read memory page from process.");
Expand Down
88 changes: 62 additions & 26 deletions SleepHunter/Models/Skillbook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
using SleepHunter.Media;
using SleepHunter.Metadata;
using SleepHunter.Settings;
using System.Net;
using SleepHunter.Win32;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace SleepHunter.Models
{
Expand Down Expand Up @@ -265,7 +269,7 @@ public void Update(ProcessMemoryAccessor accessor)
skills[i].RequiresDisarm = false;
}

skills[i].IsOnCooldown = IsSkillOnCooldown(i, version, reader);
skills[i].IsOnCooldown = IsSkillOnCooldown(i, version, reader, accessor.ProcessHandle);
}
catch { }
}
Expand All @@ -285,12 +289,12 @@ public void ResetDefaults()
}
}

bool IsSkillOnCooldown(int slot, ClientVersion version, BinaryReader reader)
bool IsSkillOnCooldown(int slot, ClientVersion version, BinaryReader reader, IntPtr processHandle)
{
if (version == null || !UpdateSkillbookCooldownPointer(version, reader))
if (version == null || !UpdateSkillbookCooldownPointer(version, reader, processHandle))
return false;

if (baseCooldownPointer == IntPtr.Zero)
if (!IsReadableMemory(processHandle, baseCooldownPointer))
return false;

long position = reader.BaseStream.Position;
Expand All @@ -309,14 +313,13 @@ bool IsSkillOnCooldown(int slot, ClientVersion version, BinaryReader reader)

var address = (long)baseCooldownPointer + (slot * cooldownVariable.Size);

reader.BaseStream.Position = address;

if (address < 0x15000000 || address > 0x30000000)
if (!IsReadableMemory(processHandle, address))
return false;

reader.BaseStream.Position = address;
address = reader.ReadUInt32();

if (address < 0x15000000 || address > 0x30000000)
if (!IsReadableMemory(processHandle, address))
return false;

if (offset.IsNegative)
Expand All @@ -325,19 +328,19 @@ bool IsSkillOnCooldown(int slot, ClientVersion version, BinaryReader reader)
address += offset.Offset;

reader.BaseStream.Position = address;
var isOnCooldown = reader.ReadBoolean();
var cooldownFlag = reader.ReadByte();

return isOnCooldown;
return cooldownFlag != 0x00;
}
catch
{
baseCooldownPointer = IntPtr.Zero;
ResetCooldownPointer();
return false;
}
finally { reader.BaseStream.Position = position; }
}

bool UpdateSkillbookCooldownPointer(ClientVersion version, BinaryReader reader)
bool UpdateSkillbookCooldownPointer(ClientVersion version, BinaryReader reader, IntPtr processHandle)
{
if (version == null)
return false;
Expand All @@ -353,29 +356,62 @@ bool UpdateSkillbookCooldownPointer(ClientVersion version, BinaryReader reader)
if (baseCooldownPointer != IntPtr.Zero)
return true;

var ptrs = scanner.FindAllUInt32((uint)cooldownVariable.Address).ToList();
var firstMatch = ptrs.FirstOrDefault();
var ptrs = scanner.FindAllUInt32((uint)cooldownVariable.Address)
.Select(ptr =>
{
if (cooldownVariable.Offset.IsNegative)
ptr = (IntPtr)((uint)ptr - (uint)cooldownVariable.Offset.Offset);
else
ptr = (IntPtr)((uint)ptr + (uint)cooldownVariable.Offset.Offset);

return ptr;
})
.Where(ptr => IsReadableMemory(processHandle, ptr))
.ToList();


foreach (var ptr in ptrs)
{
if (ptr == IntPtr.Zero)
continue;

if (firstMatch == IntPtr.Zero)
return false;
reader.BaseStream.Position = ptr;
var cooldownPtr = reader.ReadUInt32();

if (cooldownVariable.Offset.IsNegative)
firstMatch = (IntPtr)((uint)firstMatch - (uint)cooldownVariable.Offset.Offset);
else
firstMatch = (IntPtr)((uint)firstMatch + (uint)cooldownVariable.Offset.Offset);
if (cooldownPtr == 0 || !IsReadableMemory(processHandle, cooldownPtr))
continue;

var address = (long)firstMatch;

reader.BaseStream.Position = address;
address = reader.ReadUInt32();
baseCooldownPointer = (IntPtr)cooldownPtr;
Debug.WriteLine($"Found cooldown timers pointer = {cooldownPtr:X}");
return true;
}

baseCooldownPointer = (IntPtr)address;
return true;
return false;
}
catch { baseCooldownPointer = IntPtr.Zero; return false; }
finally { reader.BaseStream.Position = position; }
}

static bool IsReadableMemory(IntPtr processHandle, long address)
{
if (address <= 0)
return false;

var sizeOfMemoryInfo = Marshal.SizeOf(typeof(MemoryBasicInformation));
var byteCount = (int)NativeMethods.VirtualQueryEx(processHandle, (IntPtr)address, out var memoryInfo, sizeOfMemoryInfo);

if (byteCount <= 0)
return false;

if (memoryInfo.Type != VirtualMemoryType.Private)
return false;

if (memoryInfo.State == VirtualMemoryStatus.Free)
return false;

return true;
}

#region IEnumerable Methods
public IEnumerator<Skill> GetEnumerator()
{
Expand Down
2 changes: 1 addition & 1 deletion SleepHunter/SleepHunter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/ewrogers/SleepHunter4</RepositoryUrl>
<PackageProjectUrl>https://github.com/ewrogers/SleepHunter4</PackageProjectUrl>
<AssemblyVersion>4.5.3.0</AssemblyVersion>
<AssemblyVersion>4.5.4.0</AssemblyVersion>
<Copyright>2023 Erik 'SiLo' Rogers</Copyright>
<Description>Dark Ages Automation Tool</Description>
<Title>SleepHunter</Title>
Expand Down

0 comments on commit 7223797

Please sign in to comment.