【问题标题】:ReadProcessMemory Read string until NULLReadProcessMemory 读取字符串直到 NULL
【发布时间】:2019-11-27 10:56:58
【问题描述】:

我正在尝试从进程内存中读取字符串“845120”,但遇到了一些麻烦...

我知道“845120”是一个数值,但在某些情况下它可以是字母数字,这就是为什么它是一个字符串而不是一个 4 字节整数。

这是我的 Memory 类,其中包含所有处理内存的函数:

private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);

public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
    var buffer = new byte[IntPtr.Size];
    foreach (int i in offsets)
    {
        ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);

        ptr = (IntPtr.Size == 4)
        ? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
        : ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
    }
    return ptr;
}

public static IntPtr GetModuleBaseAddress(Process proc, string modName)
{
    IntPtr addr = IntPtr.Zero;

    foreach (ProcessModule m in proc.Modules)
    {
        if (m.ModuleName == modName)
        {
            addr = m.BaseAddress;
            break;
        }
    }
    return addr;
}

public static string ReadStringUntilNULL(string EXENAME, int Address)
{
    string value = "";
    bool endOfString = false;
    int counter = 0;
    while (!endOfString)
    {
        if (ReadInt8(EXENAME, Address + counter) > (byte)0)
        {
            value += (char)ReadInt8(EXENAME, Address + counter);
        }
        else
        {
            return value;
        }
        counter++;
    }
    return value;
}

这是我用来调用这些函数的代码:

Process process = null;

while(process == null)
{
    process = Process.GetProcessesByName("client_dx").FirstOrDefault();
}

var hProc = Memory.OpenProcess(0x00000010, false, process.Id);

var modBase = Memory.GetModuleBaseAddress(process, "client_dx.exe");

var addr = Memory.FindDMAAddy(hProc, (IntPtr)(modBase + 0x003393AC), new int[] { 0x30, 0x374, 0x2C, 0x0, 0x14, 0x48, 0x10 });

var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr);

Debug.WriteLine(acc);

在这一行之前它运行良好:

var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr);

所以var addr 的地址正确,但var acc 没有得到预期的结果。

我收到此错误:无法从 'System.IntPtr' 转换为 'int'

好的,所以它需要一个整数,我给出一个指针......所以我用 ToInt32() 进行了测试

var acc = Memory.ReadStringUntilNULL("client_dx.exe", addr.ToInt32());

addr.ToInt32() 操作返回 262959880,据我所知,这甚至不是地址

我得到一个空字符串,来自 Memory 类的 ReadStringUntilNULL 函数它只循环一次..

值为:addr 0x0fac7308 System.IntPtracc "" string

如何从内存中读取该字符串?或者如何正确传递参数?

【问题讨论】:

  • 您必须阅读所有字符,直到获得 0x00。我知道你的代码在做什么。我只是告诉你获得正确结果的正确方法。在二进制文件中使用字符串方法是错误的。

标签: c# memory


【解决方案1】:

我终于写了一个类,让我可以读取字符串直到为空:

public class NewMem
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll")]
    public static extern bool ReadProcessMemory(int hProcess, int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); 

    public Process Process { get; set; }

    public static IntPtr GetModuleBaseAddress(Process proc, string modName)
    {
        IntPtr addr = IntPtr.Zero;

        foreach (ProcessModule m in proc.Modules)
        {
            if (m.ModuleName == modName)
            {
                addr = m.BaseAddress;
                break;
            }
        }
        return addr;
    }

    public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
    {
        var buffer = new byte[IntPtr.Size];
        foreach (int i in offsets)
        {
            ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);

            ptr = (IntPtr.Size == 4)
            ? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
            : ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
        }
        return ptr;
    }

    public string ReadStringASCII(IntPtr address)
    {
        var myString = "";

        for (int i = 1; i < 50; i++)
        {
            var bytes = ReadMemory(address, i);
            if (bytes[(i-1)] == 0)
            {                    
                return myString;
            }
            myString = Encoding.ASCII.GetString(bytes);
        }

        return myString;
    }

    public byte[] ReadMemory(IntPtr address, int size)
    {
        var buffer = new byte[size];
        var bytesRead = 0;

        ReadProcessMemory((int)Process.Handle, (int)address, buffer, buffer.Length, ref bytesRead);

        return buffer;

    }
}

这是我的代码:

NewMem MClass = new NewMem();

var client = Process.GetProcessesByName("client_dx").FirstOrDefault();

MClass.Process = client;

// Get handle to process
var hProc = NewMem.OpenProcess(0x00000010, false, client.Id);

// Get base module
var modBase = NewMem.GetModuleBaseAddress(client, "client_dx.exe");

// Get relative base address
var vBasePointer = NewMem.FindDMAAddy(hProc, (IntPtr)(modBase + 0x55F870), new int[] { 0 });

// Get string
if (vBasePointer != IntPtr.Zero)
{
    var vNameAddress = vBasePointer + 0x20;
    var vName = MClass.ReadStringASCII(vNameAddress);
}

找到“0”时它会停止读取,但您始终可以设置一些例外或技巧,我没有找到更简洁的方法来做到这一点,但它正在工作:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 2014-05-09
    • 1970-01-01
    • 2011-10-29
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    相关资源
    最近更新 更多