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

时间:2017-06-01 18:36:32

标签: c#

我正在制作类似于作弊引擎的内存扫描程序应用程序,但想在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 lib和我的应用程序中的方法以适应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();
    }
}
  

测试闪存过程..   firefox ..&lt; 32位进程&gt;   chrome ..&lt; 64 bit process&gt;   要测试的网址:https://apps.facebook.com/candycrushsoda

     

要搜索的字节数组作为测试:60 ?? ?? ?? ?? ?? ?? ?? ?? 01 ?? ?? 00 01 44 ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 2A 12 10 00 00 29

     

它应该给出1个结果

     

在firefox中 - Flashplayerplugin它工作正常,

     chrome中的

- 包含模块pepflashplayer.dll的进程之一&gt;没有结果,因为chrome是64位进程。

     

要验证我使用cheatengine进行了双重检查,在这两种情况下都能正确找到aob

2 个答案:

答案 0 :(得分:2)

我尝试了你的代码,对我来说,在检查64位进程时,它会产生算术溢出:

      Addy = new IntPtr(memInfo.BaseAddress.ToInt32() + (int) memInfo.RegionSize);

(亲自试试,打开Build / Advanced ... /在项目设置中检查算术......)

在查询64位进程时,VirtualQueryEx可能会用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. 在更新代码之后使用64位算术,无论它使用BaseAddress还是RegionSize(例如使它们成为IntPtr并使用.ToInt64()而不是.ToInt32())

答案 1 :(得分:1)

对..所以首先我必须使用任何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