简体   繁体   English

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

[英]Searching Memory For Specific Values C# (Xbox 360)

EDIT: I think I have an idea of a possible solution for the actual searching of values. 编辑:我想我有一个实际的值搜索可能的解决方案的想法。 By making sure the user input ends in 0 the issue should be resolved. 通过确保用户输入以0结尾,应该可以解决该问题。 This would involve subtracting the last digit from the uint (which I do not know how to get, unless I go the convert to string, trim end back to uint method which is ugly but I guess it could work) and then subtracting it. 这将涉及从uint中减去最后一位(我不知道如何获得,除非我将转换为字符串,将末端修剪回uint方法很丑陋,但我想它可以工作),然后减去它。 If anyone has any tips on how to do this please help me out! 如果有人对此有任何提示,请帮助我!

I've been working on a program to search memory on the Xbox 360 for specific values, if you are familiar, it is similar to "Cheat Engine". 我一直在研究一种程序,用于在Xbox 360上搜索内存以获取特定值,如果您熟悉的话,它类似于“作弊引擎”。 I've gotten the basics down, but I just ran into an issue. 我已经掌握了基础知识,但是遇到了一个问题。 My method to search memory is dependent on starting your search at an address that will line up with your value. 我搜索内存的方法取决于在与您的值一致的地址处开始搜索。 If that doesn't make sense to you here is the code: 如果这对您没有意义,请使用以下代码:

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
        }
    }

As you can see, the code is kept to a minimum and it's also about as fast as possible when it comes to recovering memory from a console. 如您所见,将代码保持在最低限度,并且从控制台恢复内存时,代码也要尽可能快。 But, if the 4 bytes it recovers don't line up with the value, it will never return what you want. 但是,如果恢复的4个字节与该值不一致,它将永远不会返回您想要的内容。 That's obviously a serious issue because the user won't know where their value is or what address to start at to return the correct value. 这显然是一个严重的问题,因为用户将不知道其值在哪里或从何地址开始以返回正确的值。 I then attempted to use the following code to fix the issue: 然后,我尝试使用以下代码解决此问题:

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");
    }

There is a lot more code, but essentially it does the same thing, just using a file. 还有很多代码,但是本质上,它只是使用文件来完成相同的事情。 My original goal was to have users be able to input their own memory blocks to be searched, but right now it seems that just won't work. 我最初的目标是让用户能够输入自己要搜索的内存块,但是现在看来,这只是行不通的。 I do not really want to have the program search all of the memory because that might end up being a slow process (depending on the size of the process being dumped) and often times the values being looked for can be narrowed down to areas of writeable code, removing junk addresses from the executable portion of the process. 我并不是很想让程序搜索所有的内存,因为这最终可能是一个缓慢的进程(取决于转储的进程的大小),并且通常情况下,所寻找的值可以缩小到可写区域代码,从进程的可执行部分中删除垃圾地址。 I am just looking to see if anyone has any suggestions, I was thinking I could possibly get the entry address from the process (I have a function for it) and using a little math correct user input addresses to work properly but I wasn't entirely sure how to do it. 我只是想看看是否有人有任何建议,我想我可以从流程中获取条目地址(我有一个功能),并使用一些数学正确的用户输入地址来正常工作,但我没有完全确定该怎么做。 If anyone has any suggestions or solutions I'd appreciate any help I can get. 如果有人有任何建议或解决方案,我将不胜感激。 If any of my post needs to be clarified/cleaned up please let me know, I'll be glad to do anything that might help me to an answer. 如果需要澄清/清理我的任何帖子,请告诉我,我将很高兴做任何可能有助于回答的事情。 Thanks! 谢谢!

Edit: Temporary (hopefully) Solution: 编辑:临时(希望)解决方案:

When I load addresses into the tool they are loaded as strings from a text file, then a conversion to uint is attempted. 当我将地址加载到工具中时,它们将作为文本文件中的字符串加载,然后尝试转换为uint。 I solved the not even issue using the following code: 我使用以下代码解决了偶数问题:

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

Instead of dumping memory to disk and reading every iteration, scan the target process' memory in chunks, and then marshal the data to leverage the efficiency of pointer arithmetic. 与其将内存转储到磁盘并读取每次迭代,不如逐块扫描目标进程的内存,然后封送数据以利用指针算术的效率。

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();
        }
    }
}

Test Results 检测结果

Duration: 1.142 seconds 持续时间:1.142秒
Found: 3204 找到的:3204

Create a generic class to make type marshaling easier, like so: 创建一个通用类以简化类型封送处理,如下所示:

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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM