在内存中搜索特定值C#(Xbox 360)

时间:2013-10-28 17:36:48

标签: c# search memory byte xbox360

编辑:我想我已经知道了实际搜索价值的可能解决方案。通过确保用户输入以0结尾,问题应该得到解决。这将涉及从uint中减去最后一个数字(我不知道如何获取,除非我转换为字符串,修剪结束回uint方法,这是丑陋但我想它可以工作)然后减去它。如果有人有任何关于如何做的提示,请帮助我!

我一直致力于在Xbox 360上搜索特定值的内存程序,如果您熟悉,它类似于“作弊引擎”。我已经掌握了基础知识,但我遇到了一个问题。我搜索内存的方法取决于在与您的值对齐的地址开始搜索。如果这对你没有意义,那么代码是:

private void searchInt32(int Value, uint Address, uint BytesToSearch)
    {
        for (uint i = 0; i <= BytesToSearch; i+=4)
        {
            int recoveredMem = XboxSupport.littleEndtoInt(XboxSupport.GetMem(Address + i, 4), 0);
            //Recover Memory (As Bytes) and convert to integer from address (incremented based on for loop)
            if (recoveredMem == Value) //Check if recovered mem = search value
            {
                writeToFile(Address + i, Convert.ToString(Value)); //If recovered mem = search value, write to a text file
            }
            siStatus.Caption = String.Format("Searching Bytes {0} out of {1}...", i, BytesToSearch); //Update status caption
        }
    }

正如您所看到的,代码保持最小,并且在从控制台恢复内存时也尽可能快。但是,如果恢复的4个字节不与值对齐,它将永远不会返回您想要的内容。这显然是一个严重的问题,因为用户不会知道它们的值在哪里或者从哪个地址开始返回正确的值。然后我尝试使用以下代码来解决问题:

private void searchUInt32(uint Value, uint Address, uint BytesToSearch)
    {

        siStatus.Caption = String.Format("Recovering Memory...");
        byte[] data = XboxSupport.GetMem(Address, BytesToSearch); //Dump Console Memory
        FileStream output = new FileStream("SearchData.dat", FileMode.Create);
        BinaryWriter writer = new BinaryWriter(output);
        writer.Write(data); //Write dump to file
        writer.Close();
        output = new FileStream("SearchData.dat", FileMode.Open);
        BinaryReader reader = new BinaryReader(output); //Open dumped file
        for (uint i = 0; i *4 < reader.BaseStream.Length; i++)
        {
            byte[] bytes = reader.ReadBytes(4); //Read the 4 bytes
            Array.Reverse(bytes);
            uint currentValue = BitConverter.ToUInt32(bytes, 0); //Convert to UInt
            if(currentValue == Value) //Compare
                writeToFile(Address + i * 4, Convert.ToString(Value));
            siStatus.Caption = String.Format("Searching Bytes {0} out of {1}...", i * 4, BytesToSearch);
        }
        reader.Close();
        File.Delete("SearchData.dat");
    }

有很多代码,但基本上它只是使用一个文件做同样的事情。我最初的目标是让用户能够输入他们自己的内存块进行搜索,但现在看起来似乎无法正常工作。我真的不想让程序搜索所有内存,因为这可能最终是一个缓慢的过程(取决于被转储的进程的大小),并且通常所寻找的值可以缩小到可写区域代码,从进程的可执行部分中删除垃圾邮件地址。我只是想看看是否有人有任何建议,我想我可能从过程中得到入口地址(我有一个功能)并使用一些数学正确的用户输入地址工作正常但我不是完全确定如何做到这一点。如果有人有任何建议或解决方案,我会感谢任何帮助。如果我的任何帖子需要澄清/清理,请告诉我,我很乐意做任何可能帮助我回答的事情。 谢谢!

编辑:临时(希望)解决方案:

当我将地址加载到工具中时,它们将作为文本文件中的字符串加载,然后尝试转换为uint。我使用以下代码解决了问题:

sA[0] = sA[0].Remove(sA[0].Length - 1) + "0"; //Remove last character and replace w/ 0
//Add 16 to the search length

1 个答案:

答案 0 :(得分:0)

不是将内存转储到磁盘并读取每次迭代,而是扫描目标进程&#39;以块为单位的内存,然后封送数据以利用指针运算的效率。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace MemoryScan {
    internal class Program {
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);

        private static unsafe void Main(string[] args) {
            Process process = Process.GetProcessesByName("notepad")[0]; //example target process

            int search = 100;  //search value
            int segment = 0x10000; //avoid the large object heap (> 84k)
            int range = 0x7FFFFFFF - segment; ; //32-bit example

            int bytesRead;
            List<int> addresses = new List<int>();

            DateTime start = DateTime.Now;

            for (int i = 0; i < range; i += segment) {
                byte[] buffer = new byte[segment];

                if (!ReadProcessMemory(process.Handle, new IntPtr(i), buffer, segment, out bytesRead)) {
                    continue;
                }

                IntPtr data = Marshal.AllocHGlobal(bytesRead);
                Marshal.Copy(buffer, 0, data, bytesRead);

                for (int j = 0; j < bytesRead; j++) {
                    int current = *(int*)(data + j);

                    if (current == search) {
                        addresses.Add(i + j);
                    }
                }

                Marshal.FreeHGlobal(data);
            }

            Console.WriteLine("Duration: {0} seconds", (DateTime.Now - start).TotalSeconds);
            Console.WriteLine("Found: {0}", addresses.Count);
            Console.ReadLine();
        }
    }
}

测试结果

持续时间:1.142秒
发现:3204

创建一个通用类,使类型编组变得更容易,如下所示:

public static class MarshalHelper
{
    public unsafe static T Read<T>(IntPtr address)
    {
        object value;

        switch (Type.GetTypeCode(typeof(T)))
        {
            case TypeCode.Int16:
                value = *(short*)address;
                break;
            case TypeCode.Int32:
                value = *(int*)address;
                break;
            case TypeCode.Int64:
                value = *(long*)address;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }

        return (T)value;
    }
}