С# Многоуровневые указатели неверны в последнем вычислении

В настоящее время я пытаюсь реализовать чтение памяти на С# по базовым указателям, найденным с помощью Cheat Engine. Я на 100% уверен, что нашел правильные указатели и смещения, так как они прекрасно работают в Cheat-Engine даже между перезагрузками.

Сейчас я реализую его на С#, у меня не было проблем с одноуровневыми точками, но по какой-то причине я не могу заставить работать свой последний многоуровневый указатель.

Все идет хорошо, пока не будет добавлено последнее значение, а затем оно вернет мне что-то «случайное», это указатели, которые я нашел, и я вижу, что это работает в Cheat Engine.

введите здесь описание изображения

Это моя реализация на С#:

public static int ReadFromPointer(int address, int[] offsets)
{
    Console.WriteLine("----------");
    Console.WriteLine("Address: " + address);
    int ptr = ReadPointer(address);
    Console.WriteLine($"Pointer returned as int: {ptr}, hex: {ptr:X}");
    foreach (var offset in offsets)
    {
        Console.WriteLine($"Adding offset: {offset:X} to Pointer: {ptr:X}");
        ptr = ReadPointer(ptr + offset);
        Console.WriteLine($"Pointer returned as int: {ptr}, hex: {ptr:X}");
    }
    Console.WriteLine("----------");
    return ptr;
}

private static int ReadPointer(int adress)
{
    int ptrNext;
    int bytesRead = 0;
    byte[] _Value = new byte[4];
    ReadProcessMemory((IntPtr)ProcessHandle, (IntPtr)adress, _Value, IntPtr.Size, ref bytesRead);
    ptrNext = BitConverter.ToInt32(_Value, 0);
    return ptrNext;
}

и я называю это, используя следующее:

var valueToFind = ProcessHelper.ReadFromPointer((int)baseAddress + 0x00C45A5C, new []{ 0xEC, 0x1C, 0x178, 0x74, 0x458 });

Теперь идет «случайная» часть, все указатели добавляются правильно, кроме последнего, когда необходимо добавить 0x458 к указателю 1E138F80, это должно вернуть 1E1393D8, но в итоге возвращает «41C00000» введите здесь описание изображения

Я не уверен, связано ли это с тем, что мой последний указатель больше не составляет 4 байта, или происходит какое-то преобразование, которое смешивает его. Любая помощь здесь будет принята с благодарностью!


person user1725266    schedule 03.12.2018    source источник
comment
Однако ваш код не печатает результат 0x458 + 0x1E138F80 — он печатает результат чтения памяти по адресу 0x458 + 1E138F80. Таким образом, предположительно память по адресу 1e139830 имеет значение 41C00000.   -  person Jon Skeet    schedule 03.12.2018
comment
Кхм... Вы печатаете не сам адрес указателя, вы печатаете содержимое памяти, найденное по адресу памяти 0x1E138F80 + 0x480   -  person    schedule 03.12.2018
comment
Обратите внимание на скриншот вашего CheatEngine, обратите внимание на символ между значением указателя и результатом. Для 0x1E138F80 + 0x480 используется символ = (т. е. показывает результирующий адрес указателя), тогда как для любых других указателей + смещения используется символ ->, включая квадратные скобки [ ] вокруг адреса указателя (разыменование указателя, отображение данных памяти по результирующему адресу указателя).   -  person    schedule 03.12.2018
comment
Хорошо, что вы также проверяете, есть ли ошибки в ReadProcessMemory. См. ответ значение и используйте GetLastError. Но вероятно 0x41C0000 это значение на 0x1E138F80 + 0x458   -  person Kevin Kouketsu    schedule 03.12.2018
comment
@elgonzo Заметка о CheatEngine была очень полезной, пожалуйста, опубликуйте ее как ответ, чтобы я мог ее принять. Думал, что мне придется сместить на 1 раз больше, чем нужно, а затем прочитать адрес. Работает как шарм!   -  person user1725266    schedule 04.12.2018


Ответы (1)


Ваша проблема в том, что после добавления последнего смещения вы снова разыгрываете его, как будто этот адрес указывает на переменную, адрес которой вы пытаетесь получить. На самом деле, в этот момент адрес является адресом вашей переменной, а не указателем на нее. Когда будет добавлено последнее смещение, вы должны остановиться и вместо этого напечатать эту переменную.

Я уверен, что изменение:

foreach (var offset in offsets)

to

for (var i = 0; i < offsets.Length; ++i)

и изменение

ptr = ReadPointer(ptr + offset);

to

ptr = ReadPointer(ptr + offset[i]);

исправит это.

Распечатайте после завершения цикла for, и он должен напечатать правильный адрес.

Если это не поможет, я подготовил для вас замену функции:

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;
}
person GuidedHacking    schedule 25.05.2019