 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
KryziK Expert Cheater
Reputation: 3
Joined: 16 Aug 2009 Posts: 199
|
Posted: Tue May 31, 2011 7:42 pm Post subject: C# Memory Scanning |
|
|
Alright, so I've seen plenty of these posts on the forums, but I haven't found one with a straight up answer. Here is my code:
Code: | [DllImport("kernel32.dll")]
internal static extern Int32 VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out Memory.MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);
private MEMORY_BASIC_INFORMATION MBI;
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION
{
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public uint AllocationProtect;
public IntPtr RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
public int AOBScan(byte[] bBytesToSearch, long iStartAddress = 0, long iEndAddress = 0x7FFFFFFF)
{
long iAddress = iStartAddress; IntPtr ptrBytesRead; byte[] bBuffer;
do
{
int iRead = API.VirtualQueryEx(hReadProcess, (IntPtr)iAddress, out MBI, (uint)Marshal.SizeOf(MBI));
if ((iRead > 0) && ((int)MBI.RegionSize > 0))
{
bBuffer = new byte[(int)MBI.RegionSize];
API.ReadProcessMemory(hReadProcess, MBI.BaseAddress, bBuffer, (uint)bBuffer.Length, out ptrBytesRead);
//Search Buffer for specified bytes. Not included so I don't have to include the FindBytesinByteArray function.
}
iAddress = (long)(MBI.BaseAddress.ToInt64() + MBI.RegionSize.ToInt64());
} while (iAddress <= iEndAddress);
return 0;
} |
To be clear, this code WORKS, however, I feel like I should add something to it to make it safer/easier to use/debug. I haven't included any Types like MEM_PRIVATE, etc., or States like MEM_COMMIT, etc.. Should these be added or should any additional checks be made within the function? Sorry if I'm being unclear. I'm simply asking if there's anything I've overlooked that I should include as a good practice.
Also, I've seen many different DLLImports for this function. This one seems to work while the others didn't, but just to make sure, is this correct, or will I somehow lose some data when it's in the wrong format? I'm more concerned about the struct than the import itself.
|
|
Back to top |
|
 |
atom0s Moderator
Reputation: 205
Joined: 25 Jan 2006 Posts: 8585 Location: 127.0.0.1
|
Posted: Wed Jun 01, 2011 11:48 am Post subject: |
|
|
This is how I did it a while back:
Code: | using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
//
// sigScan C# Implementation - Written by atom0s [aka Wiccaan]
// Class Version: 2.0.0
//
// [ CHANGE LOG ] -------------------------------------------------------------------------
//
// 2.0.0
// - Updated to no longer require unsafe or fixed code.
// - Removed unneeded methods and code.
//
// 1.0.0
// - First version written and release.
//
// [ CREDITS ] ----------------------------------------------------------------------------
//
// sigScan is based on the FindPattern code written by
// dom1n1k and Patrick at GameDeception.net
//
// Full credit to them for the purpose of this code. I, atom0s, simply
// take credit for converting it to C#.
//
// [ USAGE ] ------------------------------------------------------------------------------
//
// Examples:
//
// SigScan _sigScan = new SigScan();
// _sigScan.Process = someProc;
// _sigScan.Address = new IntPtr(0x123456);
// _sigScan.Size = 0x1000;
// IntPtr pAddr = _sigScan.FindPattern(new byte[]{ 0xFF, 0xFF, 0xFF, 0xFF, 0x51, 0x55, 0xFC, 0x11 }, "xxxx?xx?", 12);
//
// SigScan _sigScan = new SigScan(someProc, new IntPtr(0x123456), 0x1000);
// IntPtr pAddr = _sigScan.FindPattern(new byte[]{ 0xFF, 0xFF, 0xFF, 0xFF, 0x51, 0x55, 0xFC, 0x11 }, "xxxx?xx?", 12);
//
// ----------------------------------------------------------------------------------------
namespace SigScan.Classes
{
public class SigScan
{
/// <summary>
/// ReadProcessMemory
///
/// API import definition for ReadProcessMemory.
/// </summary>
/// <param name="hProcess">Handle to the process we want to read from.</param>
/// <param name="lpBaseAddress">The base address to start reading from.</param>
/// <param name="lpBuffer">The return buffer to write the read data to.</param>
/// <param name="dwSize">The size of data we wish to read.</param>
/// <param name="lpNumberOfBytesRead">The number of bytes successfully read.</param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out()] byte[] lpBuffer,
int dwSize,
out int lpNumberOfBytesRead
);
/// <summary>
/// m_vDumpedRegion
///
/// The memory dumped from the external process.
/// </summary>
private byte[] m_vDumpedRegion;
/// <summary>
/// m_vProcess
///
/// The process we want to read the memory of.
/// </summary>
private Process m_vProcess;
/// <summary>
/// m_vAddress
///
/// The starting address we want to begin reading at.
/// </summary>
private IntPtr m_vAddress;
/// <summary>
/// m_vSize
///
/// The number of bytes we wish to read from the process.
/// </summary>
private Int32 m_vSize;
#region "sigScan Class Construction"
/// <summary>
/// SigScan
///
/// Main class constructor that uses no params.
/// Simply initializes the class properties and
/// expects the user to set them later.
/// </summary>
public SigScan()
{
this.m_vProcess = null;
this.m_vAddress = IntPtr.Zero;
this.m_vSize = 0;
this.m_vDumpedRegion = null;
}
/// <summary>
/// SigScan
///
/// Overloaded class constructor that sets the class
/// properties during construction.
/// </summary>
/// <param name="proc">The process to dump the memory from.</param>
/// <param name="addr">The started address to begin the dump.</param>
/// <param name="size">The size of the dump.</param>
public SigScan(Process proc, IntPtr addr, int size)
{
this.m_vProcess = proc;
this.m_vAddress = addr;
this.m_vSize = size;
}
#endregion
#region "sigScan Class Private Methods"
/// <summary>
/// DumpMemory
///
/// Internal memory dump function that uses the set class
/// properties to dump a memory region.
/// </summary>
/// <returns>Boolean based on RPM results and valid properties.</returns>
private bool DumpMemory()
{
try
{
// Checks to ensure we have valid data.
if (this.m_vProcess == null)
return false;
if (this.m_vProcess.HasExited == true)
return false;
if (this.m_vAddress == IntPtr.Zero)
return false;
if (this.m_vSize == 0)
return false;
// Create the region space to dump into.
this.m_vDumpedRegion = new byte[this.m_vSize];
bool bReturn = false;
int nBytesRead = 0;
// Dump the memory.
bReturn = ReadProcessMemory(
this.m_vProcess.Handle, this.m_vAddress, this.m_vDumpedRegion, this.m_vSize, out nBytesRead
);
// Validation checks.
if (bReturn == false || nBytesRead != this.m_vSize)
return false;
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// MaskCheck
///
/// Compares the current pattern byte to the current memory dump
/// byte to check for a match. Uses wildcards to skip bytes that
/// are deemed unneeded in the compares.
/// </summary>
/// <param name="nOffset">Offset in the dump to start at.</param>
/// <param name="btPattern">Pattern to scan for.</param>
/// <param name="strMask">Mask to compare against.</param>
/// <returns>Boolean depending on if the pattern was found.</returns>
private bool MaskCheck(int nOffset, byte[] btPattern, string strMask)
{
// Loop the pattern and compare to the mask and dump.
for (int x = 0; x < btPattern.Length; x++)
{
// If the mask char is a wildcard, just continue.
if (strMask[x] == '?')
continue;
// If the mask char is not a wildcard, ensure a match is made in the pattern.
if ((strMask[x] == 'x') && (btPattern[x] != this.m_vDumpedRegion[nOffset + x]))
return false;
}
// The loop was successful so we found the pattern.
return true;
}
#endregion
#region "sigScan Class Public Methods"
/// <summary>
/// FindPattern
///
/// Attempts to locate the given pattern inside the dumped memory region
/// compared against the given mask. If the pattern is found, the offset
/// is added to the located address and returned to the user.
/// </summary>
/// <param name="btPattern">Byte pattern to look for in the dumped region.</param>
/// <param name="strMask">The mask string to compare against.</param>
/// <param name="nOffset">The offset added to the result address.</param>
/// <returns>IntPtr - zero if not found, address if found.</returns>
public IntPtr FindPattern(byte[] btPattern, string strMask, int nOffset)
{
try
{
// Dump the memory region if we have not dumped it yet.
if (this.m_vDumpedRegion == null || this.m_vDumpedRegion.Length == 0)
{
if (!this.DumpMemory())
return IntPtr.Zero;
}
// Ensure the mask and pattern lengths match.
if (strMask.Length != btPattern.Length)
return IntPtr.Zero;
// Loop the region and look for the pattern.
for (int x = 0; x < this.m_vDumpedRegion.Length; x++)
{
if (this.MaskCheck(x, btPattern, strMask))
{
// The pattern was found, return it.
return new IntPtr((int)this.m_vAddress + (x + nOffset));
}
}
// Pattern was not found.
return IntPtr.Zero;
}
catch (Exception ex)
{
return IntPtr.Zero;
}
}
/// <summary>
/// ResetRegion
///
/// Resets the memory dump array to nothing to allow
/// the class to redump the memory.
/// </summary>
public void ResetRegion()
{
this.m_vDumpedRegion = null;
}
#endregion
#region "sigScan Class Properties"
public Process Process
{
get { return this.m_vProcess; }
set { this.m_vProcess = value; }
}
public IntPtr Address
{
get { return this.m_vAddress; }
set { this.m_vAddress = value; }
}
public Int32 Size
{
get { return this.m_vSize; }
set { this.m_vSize = value; }
}
#endregion
}
} |
This uses the FindPattern method that is fairly commonly known, I just converted it to C#.
This doesn't wrap around VirtualQueryEx so the base + size is up to you to be sure is proper and accessible. This also dumps the memory once rather then per-each scan. If you need to rescan with a new dump each time just call ResetRegion() before scanning again.
This is from 2009 so you can write things a bit cleaner with Linq and such now.
_________________
- Retired. |
|
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
|
|