Почему я должен использовать (void*) во втором параметре функции WriteProcessMemory()?

Я пытаюсь создать игровой трейнер для игры. Я нашел нужные адреса памяти и теперь хочу записать свои значения в этот адрес.

Например: адрес боеприпасов: 0x0E9AFD07.

Это может сделать функция WriteProcessMemory() в Windows API.

Мой источник:

int main(){
    DWORD pid;
    int address = 0x0E9AFD07;
    const int data = 20;
    HWND hwnd = FindWindow(0 , "Max Payne v1.05");
    GetWindowThreadProcessId(hwnd , &pid);
    HANDLE hndl = OpenProcess(PROCESS_ALL_ACCESS , false ,pid);
    WriteProcessMemory(hndl , &address , &data , 4 , NULL); 

    return 0;
}

Но этот код не работает!

Если я должен использовать WriteProcessMemory, как показано ниже:

WriteProcessMemory(hndl , (void*)0x0E9AFD07 , &data , 4 , NULL); 

то второй параметр функции имеет тип LPVOID и я читал, что LPVOID это указатель на что угодно.

Итак, почему я не могу передать указатель на int (переменная адреса) для второго параметра?

И почему я должен использовать (void*)?


person Hossein Ahmadi    schedule 22.03.2021    source источник
comment
ой, извини . почему мы используем (void*) перед адресом?   -  person Hossein Ahmadi    schedule 22.03.2021
comment
Извините за многочисленные правки. Но уточните, пожалуйста, на каком языке (C или C++). Использование false предполагает C++, но это может быть определено (как 0) в C. А процесс OpenProcess принимает BOOL второй параметр.   -  person Adrian Mole    schedule 22.03.2021
comment
большое спасибо :))   -  person Hossein Ahmadi    schedule 22.03.2021


Ответы (2)


Обратите внимание, что два ваших фрагмента кода не эквивалентны; скорее, они просят функцию WriteProcessMemory записать данные в разные местоположения.

Во втором фрагменте вы передаете 0x0E9AFD07 (как void*), что указывает функции записывать данные в память, начиная с заданного адреса (передаваемое шестнадцатеричное значение).

Однако в первом фрагменте вы передаете адрес переменной int (которая просто содержит значение 0x0E9AFD07); это даст указание функции записать данные в расположение этой переменной - таким образом, перезаписав существующее значение 0x0E9AFD07 (или потерпев неудачу в попытке сделать это).

Если вы хотите передать адрес, хранящийся в локальной переменной, вам нужно привести значение этой переменной к указателю void*, например так:

int main(){
    DWORD pid;
    int address = 0x0E9AFD07;
    const int data = 20;
    HWND hwnd = FindWindow(0 , "Max Payne v1.05");
    GetWindowThreadProcessId(hwnd , &pid);
    HANDLE hndl = OpenProcess(PROCESS_ALL_ACCESS , false ,pid);
    // The "int" variable's VALUE is the target address, so cast/pass that...
    WriteProcessMemory(hndl , (void*)address , &data , 4 , NULL); 

    return 0;
}
person Adrian Mole    schedule 22.03.2021
comment
Хотя это относительно распространенное расширение C, оно является расширением для int, которое можно преобразовать в любой тип указателя без приведения. Даже с компиляторами C, которые предоставляют такое расширение, обычно зависит от параметров компиляции, будут ли выполняться такие преобразования. - person John Bollinger; 22.03.2021
comment
при использовании C компилятор неявно преобразует int в void* Нет, это совершенно неправильно. Если вы используете соответствующий компилятор, появится диагностическое сообщение, поскольку вы написали недопустимый C. -a-cast-issues" title="указатель из целого числа из указателя без проблем приведения"> stackoverflow.com/questions/52186834/ - person Lundin; 22.03.2021

  • Почему я должен использовать (void*)

    Потому что это то, что руководство говорит вам, что функция ожидает. Конкретно:

    lpBaseAddress

    Указатель на базовый адрес в указанном процессе, в который записываются данные. Перед передачей данных система проверяет, что все данные в базовом адресе и памяти указанного размера доступны для записи, и если они недоступны, функция завершается ошибкой.

  • По той же причине вы не можете передать адрес вашей локальной переменной, в свою очередь содержащую адрес, потому что это не то, что ожидает функция.

  • LPVOID - это просто тарабарщина Windows для void*, они идентичны.

  • Чтобы превратить целочисленный адрес в тип указателя, вам нужно выполнить приведение типов, потому что именно так были разработаны C и C++. Вы не можете назначить целое число указателю, см. Указатель из целого числа/целое число из указателя без проблем приведения.

  • Примечательно, что 0x0E9AFD07 — это смещенный адрес, поэтому запись 4-байтового целого числа по этому адресу является подозрительной.

person Lundin    schedule 22.03.2021