0

編集:実際に値を検索するための可能な解決策のアイデアがあると思います。ユーザー入力が 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
4

1 に答える 1

1

メモリをディスクにダンプしてすべての反復を読み取る代わりに、ターゲット プロセスのメモリをチャンクでスキャンし、データをマーシャリングしてポインター演算の効率を活用します。

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;
    }
}
于 2013-10-28T22:09:57.547 に答える