簡體   English   中英

在 64 位進程中使用 Boyer-Moore 算法

[英]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 位架構並相應地編寫代碼,如果您負擔得起的話。 我建議您嘗試以下操作:

  1. 將項目的平台目標更改為 x64
  2. 更新 MEMORY_BASIC_INFORMATION 以便它映射到結構的 64 位版本(備注中的底部),而不是另一個。 https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx
  3. 之后更新代碼以在使用 BaseAddress 或 RegionSize 的地方使用 64 位算術(例如,將它們設為 IntPtr 並使用 .ToInt64() 而不是 .ToInt32())

對..所以首先我必須在任何 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM