[英]Using Boyer–Moore algorithms in 64 bit processes
我正在制作一個類似於作弊引擎的內存掃描儀應用程序,但想在 C# 中做它,作為一個測試項目......所以,我使用的是一個利用https://github.com/ 的庫Adversities/Cheatool使用 Boyer-Moore。
進程檢測正在工作..並且在 32 位進程中我可以找到像`
60 8A DD 01 48 00 00 BC 88 01 04 02 00 01 44 D0 30 60 8C DD 01 46 AD 1F 00 2A 12 10 00 00 29
` 如果我使用 Boyer–Moore 方法尋找它們,則正確...
但由於某種原因,我無法在 64 位進程中找到它們。
我如何更新在 dll 庫和我的應用程序中找到的方法以適應 64 位進程? 現在,由於我對 c# 很陌生,並且喜歡試驗,我起草了一個測試應用程序:
測試應用程序代碼:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace MemTester
{
class Program
{
static void Main(string[] args)
{
Console.Title = "Memory Addres Tester [?] (PID: ?)";
//Console.Write("Process to open => ");
//string process = Console.ReadLine();
string process = " ";
int ppid = 0;
while (ppid == 0)
{
Console.Write("Process PID to open as int=> ");
string ppid2 = Console.ReadLine();
if ((ppid2 == "") || (ppid2 == null) || (ppid2.Length < 2))
{ ppid2 = "0"; }
ppid = Convert.ToInt32(ppid2);
}
while (true)
{
Console.Write("Value to scan => ");
string aob = Console.ReadLine();
if (aob == "exit") break;
MeMory(process, aob, ppid);
}
}
public abstract class Manager
{
[DllImport("KERNEL32.DLL", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr process, IntPtr address, byte[] buffer, uint size, ref uint written);
[DllImport("KERNEL32.DLL")]
public static extern bool VirtualProtectEx(IntPtr process, IntPtr address,
uint size, uint access, out uint oldProtect);
[DllImport("KERNEL32.DLL")]
public static extern int CloseHandle(IntPtr objectHandle);
[DllImport("KERNEL32.DLL")]
public static extern IntPtr OpenProcess(uint access, bool inheritHandler, uint processId);
[Flags]
public enum Protection
{
PEReadWrite = 0x40,
PReadWrite = 0x04
}
[Flags]
public enum Access
{
Synchronize = 0x100000,
StandardRightsRequired = 0x000F0000,
AllAccess = StandardRightsRequired | Synchronize | 0xFFFF
}
}
public abstract class Reader
{
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION
{
public IntPtr BaseAddress;
public IntPtr AllocationBase;
public uint AllocationProtect;
public uint RegionSize;
public uint State;
public uint Protect;
public uint Type;
}
[DllImport("KERNEL32.DLL")]
public static extern int VirtualQueryEx(IntPtr hProcess,
IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
[DllImport("KERNEL32.DLL", SetLastError = true)]
public static extern bool ReadProcessMemory(
IntPtr process, IntPtr address, byte[] buffer, uint size, ref uint read);
public List<MEMORY_BASIC_INFORMATION> MemoryRegion = new List<MEMORY_BASIC_INFORMATION>();
}
public class BoyerMoore : Reader
{
private IntPtr _processHandle;
public BoyerMoore(IntPtr processHandle)
{
_processHandle = processHandle;
}
private void MemInfo(bool unwritable)
{
IntPtr Addy = new IntPtr();
while (true)
{
MEMORY_BASIC_INFORMATION memInfo = new MEMORY_BASIC_INFORMATION();
int MemDump = VirtualQueryEx(_processHandle, Addy, out memInfo, Marshal.SizeOf(memInfo));
if (MemDump == 0) break;
if ((memInfo.State & 0x1000) != 0)
{
if (unwritable && (memInfo.Protect & 0xCC) != 0)
MemoryRegion.Add(memInfo);
else
MemoryRegion.Add(memInfo);
}
Addy = new IntPtr(memInfo.BaseAddress.ToInt32() + (int)memInfo.RegionSize);
}
}
private void BoyerAlgo(IntPtr baseAddress, byte[] memoryBrick, byte[] pattern, ref List<IntPtr> addresses)
{
int offSet = 0;
while ((offSet = Array.IndexOf(memoryBrick, pattern[0], offSet)) != -1)
{
if (pattern.Length > 1)
for (int i = 1; i < pattern.Length; i++)
{
if (memoryBrick.Length <= offSet + pattern.Length
|| pattern[i] != memoryBrick[offSet + i]) break;
if (i == pattern.Length - 1)
addresses.Add(new IntPtr((int)baseAddress + offSet));
}
else addresses.Add(new IntPtr((int)baseAddress + offSet));
offSet++;
}
}
private void BoyerAlgo(IntPtr baseAddress, byte[] memoryBrick, string pattern, ref List<IntPtr> addresses)
{
int offSet = 0;
string[] aob = pattern.Split(' ');
List<int> bytesPos = new List<int>();
for (int i = 0; i < aob.Length; i++)
if (aob[i] != "??")
bytesPos.Add(i);
if (bytesPos.Count != 0)
while ((offSet = Array.IndexOf(memoryBrick, (byte)Convert.ToInt32(aob[bytesPos[0]], 16), offSet)) != -1)
{
if (bytesPos.Count > 1)
for (int i = 1; i < bytesPos.Count; i++)
{
if (memoryBrick.Length <= offSet + pattern.Length
|| (byte)Convert.ToInt32(aob[bytesPos[i]], 16)
!= memoryBrick[(offSet - bytesPos[0]) + bytesPos[i]]) break;
if (i == bytesPos.Count - 1)
if (aob[0] == "??")
addresses.Add(new IntPtr((int)baseAddress + (offSet - bytesPos[0])));
else addresses.Add(new IntPtr((int)baseAddress + offSet));
}
else
addresses.Add(new IntPtr((int)baseAddress + (offSet - bytesPos[0])));
offSet++;
}
else
for (int i = 0; i < memoryBrick.Length; i++)
addresses.Add(new IntPtr((int)baseAddress + i));
}
public CancellationTokenSource cancelToken { get; set; } = new CancellationTokenSource();
public Task<IntPtr[]> AoByte(string pattern, bool unwritable = false)
{
if (!pattern.Contains("?"))
{
byte[] buff = pattern.Split(' ').Select(by =>
(byte)Convert.ToInt32(by, 16)).ToArray();
return Task.Run(() => { return GeneralScan(buff, unwritable); }, cancelToken.Token);
}
else return Task.Run(() => { return WCScan(pattern, unwritable); }, cancelToken.Token);
}
private IntPtr[] GeneralScan(byte[] buff, bool unwritable)
{
MemInfo(unwritable);
List<IntPtr> addresses = new List<IntPtr>();
for (int i = 0; i < MemoryRegion.Count; i++)
{
uint read = 0;
byte[] wholeMemory = new byte[MemoryRegion[i].RegionSize];
ReadProcessMemory(_processHandle, MemoryRegion[i].BaseAddress, wholeMemory,
MemoryRegion[i].RegionSize, ref read);
BoyerAlgo(MemoryRegion[i].BaseAddress, wholeMemory, buff, ref addresses);
}
return addresses.ToArray();
}
private IntPtr[] WCScan(string pattern, bool unwritable)
{
MemInfo(unwritable);
List<IntPtr> addresses = new List<IntPtr>();
for (int i = 0; i < MemoryRegion.Count; i++)
{
uint read = 0;
byte[] wholeMemory = new byte[MemoryRegion[i].RegionSize];
ReadProcessMemory(_processHandle, MemoryRegion[i].BaseAddress, wholeMemory,
MemoryRegion[i].RegionSize, ref read);
BoyerAlgo(MemoryRegion[i].BaseAddress, wholeMemory, pattern, ref addresses);
}
return addresses.ToArray();
}
}
public class MeMorybox : Manager
{
public BoyerMoore BoyerScan { get; set; }
IntPtr _processHandle;
public MeMorybox(Process process)
{
_processHandle = OpenProcess((uint)Access.AllAccess, false, (uint)process.Id);
BoyerScan = new BoyerMoore(_processHandle);
}
~MeMorybox()
{
CloseHandle(_processHandle);
}
}
static void MeMory(string process, string aob, int ppid)
{
//Process[] processList = Process.GetProcessesByName(process);
Process p = Process.GetProcessById(ppid); ;
MeMorybox notepad = new MeMorybox(p);
Console.WriteLine("Hex value of pid:"+p.Id.ToString("x8"));
var addresses = notepad.BoyerScan.AoByte(aob).GetAwaiter().GetResult();
Console.WriteLine(addresses.Length + " hits found for pid:"+ppid);
Console.WriteLine();
}
}
測試 flash 進程.. firefox..<32 位進程> chrome..<64 位進程> url 測試: https : //apps.facebook.com/candycrushsoda
要搜索的字節數組 test:60 ?? ?? ?? ?? ?? ?? ?? ?? 01 ?? ?? 00 01 44 ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 2A 12 10 00 00 29
它應該給出 1 個結果
在 firefox--Flashplayerplugin 中它工作正常,
在 chrome 中——包含模塊 pepflashplayer.dll 的進程之一 > 沒有結果,因為 chrome 是一個 64 位進程。
為了驗證我使用作弊引擎進行了雙重檢查,在兩種情況下都正確找到了 aob
我嘗試了你的代碼,對我來說,在檢查 64 位進程時,它在線上產生了算術溢出:
Addy = new IntPtr(memInfo.BaseAddress.ToInt32() + (int) memInfo.RegionSize);
(自己試試,在項目設置中開啟Build/Advanced.../Check for algorithm...)
看起來 VirtualQueryEx 在查詢 64 位進程時可能會用 Int32.MaxValue() 填充 MEMORY_BASIC_INFORMATION.BaseAddress。
我認為使其與 32 位和 64 位進程兼容的最簡單方法是僅針對 64 位架構並相應地編寫代碼,如果您負擔得起的話。 我建議您嘗試以下操作:
對..所以首先我必須在任何 cpu 上使用構建,然后取消選中“首選 32 位”
public class MeMorybox : Manager
{
public BoyerMoore BoyerScan { get; set; }
IntPtr _processHandle;
public MeMorybox(Process process)
{
_processHandle = OpenProcess((uint)Access.AllAccess, false, (uint)process.Id);
BoyerScan = new BoyerMoore(_processHandle);
}
更新為:
UIntPtr _processHandle;
public MeMorybox(Process process)
{
_processHandle = OpenProcess((uint)Access.AllAccess, false, (uint)process.Id);
BoyerScan = new BoyerMoore(_processHandle);
}
我更新了內存基本信息...:
public struct _MEMORY_BASIC_INFORMATION64
{
public ulong BaseAddress;
public ulong AllocationBase;
public int AllocationProtect;
public int __alignment1;
public ulong RegionSize;
public int State;
public int Protect;
public int Type;
public int __alignment2;
}
並通過代碼將 _MEMORY_BASIC_INFORMATION 中應用的更改以及進程句柄更改更新為 ## UIntPtr ##
還更新了:
[DllImport("KERNEL32.DLL")]
public static extern int VirtualQueryEx(UIntPtr hProcess,
UIntPtr lpAddress, out _MEMORY_BASIC_INFORMATION64 lpBuffer, int dwLength);
[DllImport("KERNEL32.DLL", SetLastError = true)]
public static extern bool ReadProcessMemory(
UIntPtr process, ulong address, byte[] buffer, ulong size, ref uint read);
public List<_MEMORY_BASIC_INFORMATION64> MemoryRegion = new List<_MEMORY_BASIC_INFORMATION64>();
[DllImport("KERNEL32.DLL", SetLastError = true)]
public static extern bool WriteProcessMemory(
UIntPtr process, ulong address, byte[] buffer, uint size, ref uint written);
[DllImport("KERNEL32.DLL")]
public static extern bool VirtualProtectEx(UIntPtr process, ulong address,
uint size, uint access, out uint oldProtect);
[DllImport("KERNEL32.DLL")]
public static extern int CloseHandle(UIntPtr objectHandle);
[DllImport("KERNEL32.DLL")]
public static extern UIntPtr OpenProcess(uint access, bool inheritHandler, uint processId);
[Flags]
public enum Protection
{
PEReadWrite = 0x40,
PReadWrite = 0x04
}
[Flags]
public enum Access
{
Synchronize = 0x100000,
StandardRightsRequired = 0x000F0000,
AllAccess = StandardRightsRequired | Synchronize | 0xFFFF
}
so, now, compiled for any cpu, it finds adreses corectly for 32 bit and 64 bit proceses
many thanks to:
@Dirk
and
@Loonquawl
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.