|
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
logicallysynced Newbie cheater Reputation: 0
Joined: 30 Mar 2016 Posts: 16
|
Posted: Thu Jul 06, 2017 9:05 am Post subject: Trouble using signature outside of CE |
|
|
Hi there,
I'm currently having some trouble with a signature I have located. I'm looking to fetch the address for a text string "HOTBAR.DAT" in memory. I know that I can find this in CE using the signature:
48 4F 54 42 41 52 2E 44 41 54 00 00 00 00 00 00 30 9F
No matter how many times I restart the game, putting that byte array into the "Find Memory" tool in CE always returns the correct position.
The problem I'm having is translating that over to my external application. I have countless other signature patterns just like this one in my application (C# based) which uses a SigScan class to fetch my memory addresses for use in the app - it has worked flawlessly for all signatures I have found EXCEPT this one.
For some reason it cannot find the above signature and I can't work out for the life of me why. I can locate it every time (even without wildcards) in CE (i also wrote an aobscan LUA script in CE to test and that works fine also) so it should translate to my scanner, but it doesn't.
Is there something I may be missing? I have attached a copy of the memory view to this post.
Description: |
|
Filesize: |
676.94 KB |
Viewed: |
11311 Time(s) |
|
|
|
Back to top |
|
|
Dark Byte Site Admin Reputation: 458
Joined: 09 May 2003 Posts: 25287 Location: The netherlands
|
Posted: Thu Jul 06, 2017 11:14 am Post subject: |
|
|
perhaps your signature scanner only scans modules
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
|
atom0s Moderator Reputation: 198
Joined: 25 Jan 2006 Posts: 8517 Location: 127.0.0.1
|
Posted: Thu Jul 06, 2017 1:25 pm Post subject: |
|
|
Also double check that your scanner is scanning pages with the proper protections. What you showed only has Read/Write protections, make sure your scanner isn't ignoring it.
_________________
- Retired. |
|
Back to top |
|
|
logicallysynced Newbie cheater Reputation: 0
Joined: 30 Mar 2016 Posts: 16
|
Posted: Thu Jul 06, 2017 5:05 pm Post subject: |
|
|
atom0s wrote: | Also double check that your scanner is scanning pages with the proper protections. What you showed only has Read/Write protections, make sure your scanner isn't ignoring it. |
Sorry for asking probably an obvious question, but would you be able to point me in the right direction to make sure the SigScan class isn't ignoring that?
And I'm not sure how to check if SigScan is only scanning modules?
I appreciate any suggestions/feedback you can give
|
|
Back to top |
|
|
atom0s Moderator Reputation: 198
Joined: 25 Jan 2006 Posts: 8517 Location: 127.0.0.1
|
Posted: Thu Jul 06, 2017 6:05 pm Post subject: |
|
|
You would have to post the code you are using for us to be able to help determine that.
_________________
- Retired. |
|
Back to top |
|
|
logicallysynced Newbie cheater Reputation: 0
Joined: 30 Mar 2016 Posts: 16
|
Posted: Thu Jul 06, 2017 7:13 pm Post subject: |
|
|
atom0s wrote: | You would have to post the code you are using for us to be able to help determine that. |
The scanner code is as follows:
Code: |
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using FFXIVAPP.Memory.Events;
using FFXIVAPP.Memory.Models;
using NLog;
namespace FFXIVAPP.Memory
{
public sealed class Scanner
{
#region Logger
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
#endregion
/// <summary>
/// </summary>
/// <param name="pSignatures"> </param>
public void LoadOffsets(IEnumerable<Signature> pSignatures)
{
IsScanning = true;
Func<bool> d = delegate
{
var sw = new Stopwatch();
sw.Start();
if (MemoryHandler.Instance.ProcessModel?.Process == null)
{
return false;
}
var signatures = new List<Signature>(pSignatures);
LoadRegions();
if (signatures.Any())
{
foreach (var signature in signatures)
{
if (signature.Value == string.Empty)
{
// doesn't need a signature scan
Locations[signature.Key] = signature;
continue;
}
signature.Value = signature.Value.Replace("*", "?"); // allows either ? or * to be used as wildcard
}
signatures.RemoveAll(a => Locations.ContainsKey(a.Key));
FindExtendedSignatures(signatures);
}
foreach (var kvp in Locations)
{
Logger.Log(LogLevel.Info, $"Signature [{kvp.Key}] Found At Address: [{((IntPtr) kvp.Value).ToString("X")}]");
}
sw.Stop();
RaiseSignaturesFound(Logger, Locations, sw.ElapsedMilliseconds);
IsScanning = false;
return true;
};
d.BeginInvoke(null, null);
}
/// <summary>
/// </summary>
private void LoadRegions()
{
try
{
_regions = new List<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION>();
var address = new IntPtr();
while (true)
{
var info = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
var result = UnsafeNativeMethods.VirtualQueryEx(MemoryHandler.Instance.ProcessHandle, address, out info, (uint) Marshal.SizeOf(info));
if (0 == result)
{
break;
}
if (0 != (info.State & MemCommit) && 0 != (info.Protect & Writable) && 0 == (info.Protect & PageGuard))
{
_regions.Add(info);
}
else
{
MemoryHandler.Instance.RaiseException(Logger, new Exception(info.ToString()));
}
address = IntPtr.Add(info.BaseAddress, info.RegionSize.ToInt32());
}
}
catch (Exception ex)
{
MemoryHandler.Instance.RaiseException(Logger, ex, true);
}
}
private void FindExtendedSignatures(IEnumerable<Signature> signatures)
{
const int bufferSize = 0x1200;
const int regionIncrement = 0x1000;
var moduleMemorySize = MemoryHandler.Instance.ProcessModel.Process.MainModule.ModuleMemorySize;
var baseAddress = MemoryHandler.Instance.ProcessModel.Process.MainModule.BaseAddress;
var searchEnd = IntPtr.Add(baseAddress, moduleMemorySize);
var searchStart = baseAddress;
var lpBuffer = new byte[bufferSize];
var notFound = new List<Signature>(signatures);
var temp = new List<Signature>();
var regionCount = 0;
while (searchStart.ToInt64() < searchEnd.ToInt64())
{
try
{
IntPtr lpNumberOfBytesRead;
var regionSize = new IntPtr(bufferSize);
if (IntPtr.Add(searchStart, bufferSize)
.ToInt64() > searchEnd.ToInt64())
{
regionSize = (IntPtr) (searchEnd.ToInt64() - searchStart.ToInt64());
}
if (UnsafeNativeMethods.ReadProcessMemory(MemoryHandler.Instance.ProcessHandle, searchStart, lpBuffer, regionSize, out lpNumberOfBytesRead))
{
foreach (var signature in notFound)
{
var idx = FindSuperSig(lpBuffer, SigToByte(signature.Value, WildCardChar));
if (idx < 0)
{
temp.Add(signature);
continue;
}
var baseResult = new IntPtr((long) (baseAddress + regionCount * regionIncrement));
var searchResult = IntPtr.Add(baseResult, idx + signature.Offset);
signature.SigScanAddress = new IntPtr(searchResult.ToInt64());
Locations.Add(signature.Key, signature);
}
notFound = new List<Signature>(temp);
temp.Clear();
}
regionCount++;
searchStart = IntPtr.Add(searchStart, regionIncrement);
}
catch (Exception ex)
{
MemoryHandler.Instance.RaiseException(Logger, ex, true);
}
}
}
/// <summary>
/// </summary>
/// <param name="buffer"></param>
/// <param name="pattern"></param>
/// <returns></returns>
private int FindSuperSig(byte[] buffer, byte[] pattern)
{
var result = -1;
if (buffer.Length <= 0 || pattern.Length <= 0 || buffer.Length < pattern.Length)
{
return result;
}
for (var i = 0; i <= buffer.Length - pattern.Length; i++)
{
if (buffer[i] != pattern[0])
{
continue;
}
if (buffer.Length > 1)
{
var matched = true;
for (var y = 1; y <= pattern.Length - 1; y++)
{
if (buffer[i + y] == pattern[y] || pattern[y] == WildCardChar)
{
continue;
}
matched = false;
break;
}
if (!matched)
{
continue;
}
result = i;
break;
}
result = i;
break;
}
return result;
}
/// <summary>
/// Convert a hex string to a binary array while preserving any wildcard characters.
/// </summary>
/// <param name="signature">A hex string "signature"</param>
/// <param name="wildcard">The byte to treat as the wildcard</param>
/// <returns>The converted binary array. Null if the conversion failed.</returns>
private byte[] SigToByte(string signature, byte wildcard)
{
var pattern = new byte[signature.Length / 2];
var hexTable = new[]
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};
try
{
for (int x = 0, i = 0; i < signature.Length; i += 2, x += 1)
{
if (signature[i] == wildcard)
{
pattern[x] = wildcard;
}
else
{
pattern[x] = (byte) (hexTable[char.ToUpper(signature[i]) - '0'] << 4 | hexTable[char.ToUpper(signature[i + 1]) - '0']);
}
}
return pattern;
}
catch
{
return null;
}
}
#region Event Raising
public event EventHandler<SignaturesFoundEvent> SignaturesFoundEvent = delegate { };
private void RaiseSignaturesFound(Logger logger, Dictionary<string, Signature> signatures, long processingTime)
{
SignaturesFoundEvent?.Invoke(this, new SignaturesFoundEvent(this, logger, signatures, processingTime));
}
#endregion
#region Property Bindings
private static Scanner _instance;
private Dictionary<string, Signature> _locations;
public static Scanner Instance
{
get { return _instance ?? (_instance = new Scanner()); }
set { _instance = value; }
}
public Dictionary<string, Signature> Locations
{
get { return _locations ?? (_locations = new Dictionary<string, Signature>()); }
private set
{
if (_locations == null)
{
_locations = new Dictionary<string, Signature>();
}
_locations = value;
}
}
#endregion
#region Constants
private const int WildCardChar = 63;
private const int MemCommit = 0x1000;
private const int PageNoAccess = 0x01;
private const int PageReadwrite = 0x04;
private const int PageWritecopy = 0x08;
private const int PageExecuteReadwrite = 0x40;
private const int PageExecuteWritecopy = 0x80;
private const int PageGuard = 0x100;
private const int Writable = PageReadwrite | PageWritecopy | PageExecuteReadwrite | PageExecuteWritecopy | PageGuard;
#endregion
#region Declarations
private List<UnsafeNativeMethods.MEMORY_BASIC_INFORMATION> _regions;
public bool IsScanning { get; set; }
#endregion
}
}
|
The full implementation can be found on github under Icehunter/ffxivapp-memory (cant post links).
|
|
Back to top |
|
|
atom0s Moderator Reputation: 198
Joined: 25 Jan 2006 Posts: 8517 Location: 127.0.0.1
|
Posted: Fri Jul 07, 2017 11:10 am Post subject: |
|
|
The code is using VirtualQueryEx to dump the regions, but is enforcing specific region flags to be met. Try altering the region flag checks to allow other types of memory to be included. His code is made specifically for FFXIV so the memory regions that his addresses are going to be in are possibly only ever in the types that he is checking.
_________________
- Retired. |
|
Back to top |
|
|
logicallysynced Newbie cheater Reputation: 0
Joined: 30 Mar 2016 Posts: 16
|
Posted: Fri Jul 07, 2017 11:26 am Post subject: |
|
|
atom0s wrote: | The code is using VirtualQueryEx to dump the regions, but is enforcing specific region flags to be met. Try altering the region flag checks to allow other types of memory to be included. His code is made specifically for FFXIV so the memory regions that his addresses are going to be in are possibly only ever in the types that he is checking. |
It's probably worth noting that I am using this for FFXIV as well.
I assume what you are referring to is this line here:
Code: |
if (0 != (info.State & MemCommit) && 0 != (info.Protect & Writable) && 0 == (info.Protect & PageGuard))
|
But I have already tried nullifying this statement and still get the same results.
Something I also tried was manually setting the searchStart and searchEnd variables to ranges close to where i can see the signature in CE, and when I do this the C# scanner finds it straight away. So I'm not really sure where that leaves me..
Is it possible this while statement
Code: |
var baseAddress = MemoryHandler.Instance.ProcessModel.Process.MainModule.BaseAddress;
var searchEnd = IntPtr.Add(baseAddress, moduleMemorySize);
var searchStart = baseAddress;
while (searchStart.ToInt64() < searchEnd.ToInt64())
|
is taking the scanner out of the scope of the allocated memory?
|
|
Back to top |
|
|
atom0s Moderator Reputation: 198
Joined: 25 Jan 2006 Posts: 8517 Location: 127.0.0.1
|
Posted: Fri Jul 07, 2017 11:58 am Post subject: |
|
|
Ah I did miss that. Yes, that is specifically enforcing it to scan the modules static memory area. You would want to instead have it search the systems min/max address range which you can obtain via GetSystemInfo.
http://www.pinvoke.net/default.aspx/kernel32.getsysteminfo
_________________
- Retired. |
|
Back to top |
|
|
logicallysynced Newbie cheater Reputation: 0
Joined: 30 Mar 2016 Posts: 16
|
Posted: Fri Jul 07, 2017 12:08 pm Post subject: |
|
|
Considering the returned min/max range from that GetSystemInfo is between 1000 and 7FFFFFFEFFFF (8DADB7FFF after subtracting the baseaddress of the main module), that range is huge and i think overflows the buffer quite quickly. Do you know of a way to break it down further?
EDIT
I realised that the _regions list generated from VirtualQueryEx was actually unimplemented. When i put that list into a foreach loop and used it to iterate my scanner of the regions, it found the signature straight up.
Thanks for all your help, I couldn't have figured it out without you
|
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|