【问题标题】:Using Base Pointers with Offset to Read Process Memory使用带偏移量的基指针来读取进程内存
【发布时间】:2016-02-14 10:07:57
【问题描述】:

我已经在网上搜索了几个小时,但我一生都无法理解为什么下面的代码不起作用。

为进程拉取的基地址似乎有误。如果我将结束地址直接硬编码到 ReadMemory 中,我会得到所需的值(所以我知道我有正确的过程和所有)。

我还没有发布 MemoryHandler 课程,因为它正在正常工作

这可能与我在 64 位 Windows 上的事实有关吗?游戏是 32 位的(安装在“Program Files (x86)”文件夹中)。

public partial class MainForm : Form
{

    Process myProcess = Process.GetProcessesByName("ffxiv").FirstOrDefault();

    public MainForm()
    {
        InitializeComponent();
    }

    private void startButton_Click(object sender, EventArgs e)
    {
        IntPtr baseAddress = myProcess.MainModule.BaseAddress;
        Console.WriteLine("Base Address: " + baseAddress.ToString("X"));

        IntPtr newAddr = IntPtr.Add(baseAddress, 0xF8BEFC);
        IntPtr finalAddr = IntPtr.Add(newAddr, 0x1690);

        int bytesRead;
        byte[] memoryOutput = MemoryHandler.ReadMemory(myProcess, finalAddr, 4, out bytesRead);

        int value = BitConverter.ToInt32(memoryOutput, 0);
        Console.WriteLine("Read Value: " + value);
    }
}

编辑:基地址是正确的,我围绕指针的代码逻辑是错误的,请参阅下面的完整答案。

【问题讨论】:

  • 基地址得到什么样的值,你怎么知道“正确”的值是什么?
  • Scott,我知道使用 Cheat Engine 的正确地址是什么(因此我得到的是错误的)。例如,这就是我如何找到指向该游戏 HP 的基本指针的方式。它告诉我 ffxiv.exe 应该有什么地址,它与我的 C# 代码给我的不同。然而,最有力的证据是,读取内存的最终输出并没有给出我的 hp(如果我将在作弊引擎中找到的最低级别地址直接硬编码到上面的读取内存函数中,我会得到正确的值)。
  • 您的代码返回什么值?什么是正确的值?在 Process Explorer 中检查正确的值。
  • 这并不重要,因为低级地址是动态的,但在 12 月份我应该得到 9460301(用作弊引擎验证),但我得到 1220000。这些数字自然只适用于上述进程的当前实例(重新启动时,这些会改变)。
  • 模块的基地址不会是奇数!

标签: c# process


【解决方案1】:

所以,大卫关于基地址不能是奇数的评论让我认为,也许我从 Cheat Engine 获得的数字实际上不是基地址。结果证明是正确的。我的代码实际上是在提取正确的基地址。我之前发布的数字(9460301)实际上是存储在内存中基地址位置的数字(不是地址本身)。

无论如何,上面的代码获取基地址并添加第一个偏移量,然后添加下一个偏移量,然后读取该地址上的内存。那是错误的,这不是多级指针的工作方式。对于每个级别,您都必须读取内存并查看地址中存储的内容。您找到的值将是您的下一个地址,您应用下一个偏移量,依此类推..

正确的代码是:

public partial class MainForm : Form
{

    Process myProcess = Process.GetProcessesByName("ffxiv").FirstOrDefault();

    public MainForm()
    {
        InitializeComponent();
    }

    private void startButton_Click(object sender, EventArgs e)
    {
        int bytesRead;

        IntPtr baseAddress = myProcess.MainModule.BaseAddress;
        Console.WriteLine("Base Address: " + baseAddress);

        IntPtr firstAddress = IntPtr.Add(baseAddress, 0xF8BEFC);
        IntPtr firstAddressValue = (IntPtr)BitConverter.ToInt32(MemoryHandler.ReadMemory(myProcess, firstAddress, 4, out bytesRead), 0);
        IntPtr finalAddr = IntPtr.Add(firstAddressValue, 0x1690);
        Console.WriteLine("Final Address: " + finalAddr.ToString("X"));

        byte[] memoryOutput = MemoryHandler.ReadMemory(myProcess, finalAddr, 4, out bytesRead);

        int value = BitConverter.ToInt32(memoryOutput, 0);
        Console.WriteLine("Read Value: " + value);
    }
}

我想知道,如何使这个非特定于 32 位窗口?我不太喜欢 Int32() 函数和随后的 IntPtr 转换,所以想知道是否有任何方法可以直接从 byte[] 到 IntPtr。我尝试了 marshal-copy 等,但无法让它工作。

再次感谢!

【讨论】:

    猜你喜欢
    • 2016-12-30
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多