Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Перехват записи в памяти процесса по определённому адресу

465
16 марта 2013 года
QWERYTY
595 / / 25.03.2012
Всем привет!

Както задавал вопрос, но с тех пор немного продвинулся.
Код:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;


function AddVectoredExceptionHandler(FirstHandler: CARDINAL; VectoredHandler: POINTER): POINTER; stdcall; external 'Kernel32.dll' name 'AddVectoredExceptionHandler';


type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;




type
  PEXCEPTION_RECORD = ^EXCEPTION_RECORD;
  EXCEPTION_RECORD = packed record
                     ExceptionCode: DWORD;
                     ExceptionFlags: DWORD;
                     ExceptionRecord: PEXCEPTION_RECORD;
                     ExceptionAddress: POINTER;
                     NumberParameters: DWORD;
                     ExceptionInformation: ULONG_PTR ;
                     end;



type
  PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
  EXCEPTION_POINTERS = packed record
                       ExceptionRecord: PEXCEPTION_RECORD;
                       ContextRecord: PCONTEXT;
                       end;




const
  CALL_LAST = 0;
  CALL_FIRST = 1;
  EXCEPTION_CONTINUE_SEARCH = $0;
  EXCEPTION_EXECUTE_HANDLER = $1;
  EXCEPTION_CONTINUE_EXECUTION = $FFFFFFFF;




var
  Form1: TForm1;
  SI: SYSTEM_INFO;
  MemAddr, MemAddr2: POINTER;
  lpflOldProtect, WriteEvent: CARDINAL;



implementation

{$R *.dfm}


   // ФУНКЦИЯ ПОТОКА ОЖИДАЮЩЕГО КОГДА ПРОИЗОЙДЁТ ЗАПИСЬ И ЗАПРЕЩАЮЩЕГО ЕЁ
function MyWaitThread(Data: POINTER): INTEGER; stdcall;
var
A: PAnsiString;
begin
   A := Data;
   repeat
   WaitForSingleObject(WriteEvent, INFINITE);
   Sleep(1);
   VirtualProtect(MemAddr, SI.dwPageSize, PAGE_READONLY, @lpflOldProtect);
   Form1.Memo1.Lines.Add(A^);
   Form1.Memo1.Lines.Add('Запись запрещена!');
   until 2 < 1;

end;



  // ОБРАБОТЧИК ИСКЛЮЧЕНИЙ ПОВЕРХ СИСТЕМНОГО
function MyVectoredHandler(ExceptionInfo: PEXCEPTION_POINTERS): INTEGER; stdcall;
begin
   if (ExceptionInfo.ExceptionRecord.ExceptionCode = EXCEPTION_ACCESS_VIOLATION) and (ExceptionInfo.ContextRecord.Eax = CARDINAL(MemAddr))then
   begin
      VirtualProtect(MemAddr, SI.dwPageSize, PAGE_READWRITE, @lpflOldProtect);
      SetEvent(WriteEvent);
      result := EXCEPTION_CONTINUE_EXECUTION;
      end
   else
   result := EXCEPTION_CONTINUE_SEARCH;
end;


 // КНОПКА ВЫЗЫВАЕТ ИСКЛЮЧЕНИЕ И ОНО ОБРАБАТЫВАЕТСЯ МОИМ ОБРАБОТЧИКОМ
procedure TForm1.Button1Click(Sender: TObject);
var
A: PAnsiString;
begin
   A := MemAddr;
   A^ := 'TeSt STRing';
end;


  // КНОПКА ВЫЗЫВАЕТ ИСКЛЮЧЕНИЕ,  НО МОЙ ОБРАБОТЧИК ЕГО НЕ ОБРАБАТЫВАЕТ
procedure TForm1.Button2Click(Sender: TObject);
var
A: PAnsiChar;
begin
   A := MemAddr2;  // Тут программа ведёт себя стандартно,  
   A^ := 'S';      // т.е. появляется сообщение  Access Violation
end;




procedure TForm1.FormCreate(Sender: TObject);
var
PrevHandler: POINTER;
HThread, TId: CARDINAL;
begin
   Memo1.Clear;
   GetSystemInfo(SI);
   MemAddr := NIL;
   MemAddr2 := NIL;
   MemAddr := VirtualAlloc(NIL, SI.dwPageSize * 10, MEM_COMMIT, PAGE_READONLY); // Выделение памяти только для чтения
   MemAddr2 := VirtualAlloc(NIL, SI.dwPageSize * 10, MEM_COMMIT, PAGE_READONLY); // Ещё
   if not Assigned(MemAddr) or not Assigned(MemAddr2) then ShowMessage('Ошибка при выделении памяти:  ' + IntToStr(GetLastError)) else
   begin

      WriteEvent := CreateEvent(NIL, FALSE, FALSE, 'Write');
      if WriteEvent = 0 then ShowMessage('Ошибка в создании объекта события:  ' + IntToStr(GetLastError));
      HThread := CreateThread(NIL, 0, Addr(MyWaitThread), MemAddr, 0, TId);
      if HThread = 0 then ShowMessage('Ошибка при создании потока:  ' + IntToStr(GetLastError));
       // Установка обработчика исключений
      PrevHandler := AddVectoredExceptionHandler(CALL_FIRST, Addr(MyVectoredHandler));
      if not Assigned(PrevHandler) then ShowMessage('Ошибка при установке обработчика исключений:  ' + IntToStr(GetLastError));

      Edit1.Text := IntToHex(CARDINAL(MemAddr), 8) + '   ' + IntToHex(CARDINAL(MemAddr2), 8);
      end;

end;



procedure TForm1.FormDestroy(Sender: TObject);
begin
   VirtualFree(MemAddr, SI.dwPageSize * 10, 0);
   VirtualFree(MemAddr2, SI.dwPageSize * 10, 0);
end;



end.
Тут отдельный поток ожидает когда будет выполнена запись и тут же запрещает писать в этот регион.
Насколько я понял(из прочитаного об исключениях) при возникновении исключения управление передаётся обработчику и если он сообщит что исключение обработано то управление опять передаётся на инструкцию вызвавшую исключение.
То есть по идее запись всё равно должна произойти не смотря на то что я сигнализировал потоку запретить запись.

На практике этот код работает, но можно ли пологаться на такие вещи в Windows ХР
260
16 марта 2013 года
Ramon
1.1K / / 16.08.2003
1. Подобная затея с радостным потоком изначально дырява как бабушкин дуршлаг
2. Полагаться на поведение векторизованных обработчиков исключений, в данном случае страничных - можно как раз начиная с XP, ибо векторизованные исключения начиная с него и введены.

PS: Бросьте дельфей на помойку, где их заслуженное место
465
16 марта 2013 года
QWERYTY
595 / / 25.03.2012
Бросать делфей не получится так просто. Там уже написано 3 библиотеки, и боюсь что на с++ или с# я завязну на долго если буду всё переделывать.

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

Одноразовый перехват вообще чёткий, но как его сделать многоразовым пока не соображу.
327
18 марта 2013 года
UserNet2008
748 / / 03.04.2010
Цитата:
после срабатывания обработчика будет выполнена, до того как другие потоки получат управление.


см.
Suspend - приостанавливает выполнение потока;
Resume - продолжает выполнение потока;
Terminate - пытается завершить поток путем установки свойства Terminated в True. Для прекращения выполнения потока во время работы, необходимо периодически проверять свойство Terminated в пределах метода Execute (см. ниже) и во всех методах, которые Execute вызывает, и выходить, если Terminated=True.
Execute - содержит основной код потока, т.е. те действия, которые Вы решили поместить в поток. Если Вы обратили внимание, этот метод абстрактный, т.е. его надо переопределять в пределах Вашего класса-потомка TThread.
Synchronize - используется для предотвращения одновременного доступа разных потоков к одному элементу VCL. Дело в том, что код VCL выполняется в главном потоке программы, так что поток должен синхронизироваться, если он использует код VCL. Параметр метода - это метод без параметров, который обычно принадлежит Вашему потоковому классу.

или
см.
Вот здесь можно создать пользовательское событие после завершения потока, проверить условия If Then и вызывать снова пользовательское событие.
Одно могу сказать как на Delfi это делается не знаю. VC++,VC#, VB знаю.
Так-что остановимся на этом:

 
Код:
procedure TMyThread.Execute;
begin
  while True do
    if Teminated then break;
end;
Это есть правда бесконечный цикл, но цикл завершается, и поток прекращает свою работу..
465
19 марта 2013 года
QWERYTY
595 / / 25.03.2012
То UserNet2008

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


Код уже написан, вчера тестировал. Программа проработала около двух часов без вылетов, при этом процент перехвата пока установить сложно(это ещё предстоит придумать какой нибудь тест) но на глаз выше 90%

Теперь нужно приступать к полному тестированию работы которая длилась несколько месяцев.
В общем будем провацировать баги, надеюсь их будет минимум.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог