#include <iostream>
#include <windows.h>
using namespace std;
int main(){
int *pv = (int*)0x1d1510; // этот адрес вызывает "Перкращение работы программы" почему?
cout << *pv;
return 0;
}
Я пытался изменить этот адресс,кто-то знает как без вылета программы и без использования функции VirtualAlloc это зделать? И еще как изменить значение по абсолютному адрессу в C++? И еще хотел добавить:адрес на который я указываю это переменная которая находиться в куче и это тестовая программа,мне надо изменнить значение этой переменной,эта переменная находиться вне программы,но при этом в куче!
Ваша программа, очевидно, выполняется на платформе с виртуальной памятью (к которым относятся в том числе и настольные компьютеры под управлением современных ОС).
Все адреса, с которыми вы работаете в вашей программе, — это адреса виртуального адресного пространства пространства, то есть воображаемой памяти. В эту память нельзя ничего записать и из нее нельзя ничего прочитать, потому что этой памяти изначально не существует, пока вы не «материализуете» соответствующий участок адресного пространства при помощи соответствующих функций системного API (VirtualAlloc
и т. п.). Без этого ни о каком «изменить значение по абсолютному адресу» не может быть и речи, ибо никакой памяти по этому адресу нет и никакого значения не существует.
Если вы запускаете программу на Windows или Linux — у вас нет прямого доступа к физической памяти, она «виртуализируется» через назначенную вашему процессу таблицу трансляции адресов:
(Иллюстрация взята из ответа на вопрос «Какую модель памяти сегментную или страничную использует windows, linux, macos?»)
Таблица эта, в свою очередь, управляется операционной системой и напрямую вашей программе недоступна.
Чтобы получить возможность доступа к определённому адресу, надо его куда-то отобразить (то есть сопоставить ему что-то и назначить права доступа). Сопоставлять можно оперативной памяти (VirtualAlloc()
), либо смещению внутри какого-то файла (MapViewOfFile()
). При этом привязка производится с точностью до страницы — одного из множества последовательно идущих блоков определённого размера (как правило 4КБ).
Однако встаёт вопрос: а нужен ли вам доступ к произвольному региону? На момент запуска процесса у вас уже отображены образ исполняемого EXE-файла (с кодом и статическими данными) и куча (для динамически создаваемых данных). В образе хранятся глобальные переменные, и так доступные без знания их адреса, а при выделении памяти в куче вы получаете относительно случайный адрес, которым и надо пользоваться в дальнейшем.
Но даже если вы скомпилируете программу для чего-нибудь без виртуальной памяти (DOS, 16-битный Windows, микроконтроллеры) — кто даст гарантию, что по указанному вами адресу 0x1d1510
уже не будут лежать чьи-то данные, распечатывать которые безопасно, а вот изменять — уже нет?
Смотрите. Как уже расписано в других ответах, под Windows (а у вас, исходя из <windows.h>
, именно эта платформа), как и под многими другими операционными системами, каждый процесс работает с виртуальной памятью: адреса имеют смысл только внутри самого процесса. Для того, чтобы записать в адрес внутри другого процесса, необходимо воспользоваться системно-зависимыми функциями.
Для Windows это функция WinAPI WriteProcessMemory
. Вот вам небольшой пример двух программ, где вы из одного экземпляра программы изменяете память другого экземпляра:
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <chrono>
#include "Windows.h"
volatile int value = 0;
int main(int argc, char* argv[])
{
std::cout << "Process id = 0x" << std::hex << GetCurrentProcessId() << std::endl;
std::cout << "Address of value = 0x" << (void*)&value << std::dec << std::endl;
while (true)
{
using namespace std::chrono_literals;
std::this_thread::sleep_for(2s);
std::cout << "value is " << value << std::endl;
}
return 0;
}
Это программа печатает адрес переменной value
, а потом в бесконечном цикле выдаёт её значения.
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include "Windows.h"
bool update_value(DWORD pid, size_t address, int value)
{
std::cout << "Updating value at process 0x" << std::hex << pid <<
", address 0x" << address << " to " << std::dec << value << std::endl;
HANDLE handle = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
if (handle == NULL)
{
std::cerr << "Can't open process" << std::endl;
return false;
}
bool result = true;
if (!WriteProcessMemory(handle, (LPVOID)address, &value, sizeof(int), NULL))
{
std::cerr << "Can't write to process memory" << std::endl;
result = false;
}
if (!CloseHandle(handle))
{
std::cerr << "Can't close handle" << std::endl;
result = false;
}
return result;
}
int main(int argc, char* argv[])
{
if (argc == 4)
{
DWORD pid;
size_t address;
int value;
std::stringstream s1(argv[1]), s2(argv[2]), s3(argv[3]);
if ((s1 >> std::hex >> pid) &&
(s2 >> std::hex >> address) &&
(s3 >> std::dec >> value))
{
return update_value(pid, address, value) ? 0 : 1;
}
}
std::cerr << "Cannot read parameters" << std::endl;
return 1;
}
Вторая программа получает с командной строки id другого процесса, адрес в нём и новое значение, и записывает в другой процесс по этому адресу новое значение.
У меня получился такой вывод на экран:
Первая программа:
...\WriteProcessMemoryTest\x64\Debug>Target.exe
Process id = 0x1ec4
Address of value = 0x00007FF76DA07620
value is 0
value is 0
value is 0
value is 0
value is 0
value is 0
value is 1
value is 1
value is 2018
value is 2018
value is 2018
value is 65538
value is 65538
value is 65538
^C
Вторая программа:
...\WriteProcessMemoryTest\x64\Debug>Updater.exe 0x1ec4 0x00007ff76da07620 1
Updating value at process 0x1ec4, address 0x7ff76da07620 to 1
...\WriteProcessMemoryTest\x64\Debug>Updater.exe 0x1ec4 0x00007ff76da07620 2018
Updating value at process 0x1ec4, address 0x7ff76da07620 to 2018
...\WriteProcessMemoryTest\x64\Debug>Updater.exe 0x1ec4 0x00007ff76da07620 65538
Updating value at process 0x1ec4, address 0x7ff76da07620 to 65538
Важное замечание. В моём примере всё произошло так гладко только потому, что переменная value
была объявлена как volatile
. Это говорит компилятору, что он не имеет права кешировать значение этой переменной в регистрах, не имеет права применять к ней обычные оптимизации (например, заметить, что она не меняется в программе, и не перечитывать её значение). В случае, когда по адресу, который вы меняете, расположена обычная переменная, значение, которое вы записываете, может быть проигнорировано. Ну а если вы при записи «промахнётесь», с хорошими шансами вы обрушите программу, в которой производите изменения.
void* q = reinterpret_cast<void*>(0x28fe94) ;
int* p = new (q)int;
*p = 5; // изменили значение
cout << *p;
данный адрес является адресом конкретного обьекта на конкретной платформе, поэтому программа будет работать
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Имеется простой проект DxЯ подключаю заголовочный и библиотеку
Возможно ли как-то добавить классу QCameraViewfinder через сигнал или слот on_click как у обычной кнопки?
Мне нужен виджет секундомера, градусника, компаса и шкалы топливаВ одном стиле