Прекращение работы программы(C++)

163
24 февраля 2018, 22:14
#include <iostream>
#include <windows.h>
using namespace std;
int main(){
int *pv = (int*)0x1d1510; // этот адрес вызывает "Перкращение работы программы" почему?
cout << *pv;
return 0;
}

Я пытался изменить этот адресс,кто-то знает как без вылета программы и без использования функции VirtualAlloc это зделать? И еще как изменить значение по абсолютному адрессу в C++? И еще хотел добавить:адрес на который я указываю это переменная которая находиться в куче и это тестовая программа,мне надо изменнить значение этой переменной,эта переменная находиться вне программы,но при этом в куче!

Answer 1

Ваша программа, очевидно, выполняется на платформе с виртуальной памятью (к которым относятся в том числе и настольные компьютеры под управлением современных ОС).

Все адреса, с которыми вы работаете в вашей программе, — это адреса виртуального адресного пространства пространства, то есть воображаемой памяти. В эту память нельзя ничего записать и из нее нельзя ничего прочитать, потому что этой памяти изначально не существует, пока вы не «материализуете» соответствующий участок адресного пространства при помощи соответствующих функций системного API (VirtualAlloc и т. п.). Без этого ни о каком «изменить значение по абсолютному адресу» не может быть и речи, ибо никакой памяти по этому адресу нет и никакого значения не существует.

Answer 2

Если вы запускаете программу на Windows или Linux — у вас нет прямого доступа к физической памяти, она «виртуализируется» через назначенную вашему процессу таблицу трансляции адресов:

(Иллюстрация взята из ответа на вопрос «Какую модель памяти сегментную или страничную использует windows, linux, macos?»)

Таблица эта, в свою очередь, управляется операционной системой и напрямую вашей программе недоступна.

Чтобы получить возможность доступа к определённому адресу, надо его куда-то отобразить (то есть сопоставить ему что-то и назначить права доступа). Сопоставлять можно оперативной памяти (VirtualAlloc()), либо смещению внутри какого-то файла (MapViewOfFile()). При этом привязка производится с точностью до страницы — одного из множества последовательно идущих блоков определённого размера (как правило 4КБ).

Однако встаёт вопрос: а нужен ли вам доступ к произвольному региону? На момент запуска процесса у вас уже отображены образ исполняемого EXE-файла (с кодом и статическими данными) и куча (для динамически создаваемых данных). В образе хранятся глобальные переменные, и так доступные без знания их адреса, а при выделении памяти в куче вы получаете относительно случайный адрес, которым и надо пользоваться в дальнейшем.

Но даже если вы скомпилируете программу для чего-нибудь без виртуальной памяти (DOS, 16-битный Windows, микроконтроллеры) — кто даст гарантию, что по указанному вами адресу 0x1d1510 уже не будут лежать чьи-то данные, распечатывать которые безопасно, а вот изменять — уже нет?

Answer 3

Смотрите. Как уже расписано в других ответах, под 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. Это говорит компилятору, что он не имеет права кешировать значение этой переменной в регистрах, не имеет права применять к ней обычные оптимизации (например, заметить, что она не меняется в программе, и не перечитывать её значение). В случае, когда по адресу, который вы меняете, расположена обычная переменная, значение, которое вы записываете, может быть проигнорировано. Ну а если вы при записи «промахнётесь», с хорошими шансами вы обрушите программу, в которой производите изменения.

Answer 4
void* q = reinterpret_cast<void*>(0x28fe94) ;
int*  p = new (q)int;
*p = 5; // изменили значение
cout << *p;

данный адрес является адресом конкретного обьекта на конкретной платформе, поэтому программа будет работать

READ ALSO
Visual Studio пересечение заголовочных файлов

Visual Studio пересечение заголовочных файлов

Имеется простой проект DxЯ подключаю заголовочный и библиотеку

190
Qt QCameraViewfinder

Qt QCameraViewfinder

Возможно ли как-то добавить классу QCameraViewfinder через сигнал или слот on_click как у обычной кнопки?

154
Есть виджеты реализованные для QT?

Есть виджеты реализованные для QT?

Мне нужен виджет секундомера, градусника, компаса и шкалы топливаВ одном стиле

156