SEH. Проблемы с установкой собственного обработчика
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
SYSTEM_INFO SI;
LPVOID MemAddr;
DWORD _memaddr;
DWORD scratch;
EXCEPTION_DISPOSITION __cdecl _except_handler(_EXCEPTION_RECORD * ExceptionRecord, LPVOID EstablisherFrame, _CONTEXT * ContextRecord, LPVOID DispatcherContext)
{
ShowMessage("111");
// Изменяем значение регистра EAX в context record таким образом, чтобы оно
// указывало на какое-либо, доступное для записи место в памяти.
// ContextRecord->Eax = (DWORD)&scratch;
// Просим ОС еще раз попытаться выполнить вызвавшую исключение инструкцию.
return ExceptionContinueExecution;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Memo1->Clear();
GetSystemInfo(&SI);
MemAddr = VirtualAlloc(NULL, SI.dwPageSize * 10, MEM_COMMIT, PAGE_NOACCESS);
_memaddr = DWORD(MemAddr);
Edit1->Text = IntToHex(int(_memaddr), 8);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
__asm
{
mov eax, _memaddr // Передаём указатель на начало региона в который нельзя писать.
mov [eax], 1 // Чтобы преднамеренно вызвать исключение
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
DWORD handler = DWORD(_except_handler);
__asm
{ // Создаем структуру EXCEPTION_REGISTRATION:
push handler // Адрес функции обработчика исключений.
push FS:[0] // Адрес предыдущего EXECEPTION_REGISTRATION.
mov FS:[0], ESP // Добавляем в связанный список EXECEPTION_REGISTRATION.
}
}
//---------------------------------------------------------------------------
Кнопка 1 работает, исключение вызывается, а вот кнопка 2 работать не хочет.
Обработчик исключений добавляется в цепочку, но после этого возникает исключение.
Т.е. при нажатии на кнопку 2 я вижу сообщение из моей функции, хотя по логике на этот момент не должен. Причём(после ряда экспериментов) установленно что сообщение появляется всегда 2 раза . Это поведение мне показалось странным ибо в делфи оно появляется вечно. Если не брать в расчёт странность самого факта появления исключения то в остальном в делфи мне кажется всё логичным, ведь причину исключения никто не устраняет, а в с++ я никак не пойму, будто после двух попыток проблема как то разрешается. Сообщения не выводятся и программа продолжает функцианировать.
И ещё одна странность, после всего этого гемороя при нажатии кнопки 1 я вижу стандартное окно с сообщением об ошибке вместо моего. Получается что мой обработчик ставится в цепочку и тут же удаляется. Вопрос сформулировать сложно в пару строк(по тому что их много), просто прокоментируйте если увидите ошибку, в ассемблере может не так сейчас нужно делать, или может есть какие ограничения о которых я не знаю
Win XP SP3, RAD Studio 2010
С++ Assembler code вызывать, через функцию.
Задача я надеюсь ясна? Перехват Access violation
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
SYSTEM_INFO SI;
LPVOID MemAddr;
DWORD _memaddr;
DWORD scratch;
DWORD handler; // глобальная переменная
Меня интересует, что говорит компилятор думаю, что ошибок нет, а предупреждения есть или тоже нет.
Дело в том, что при использования Assembler code компилятор может не правильно его понимать.
Поэтому в некоторых случаях применяют функцию или процедуру(второй вариант под ?):
Объявляете функцию пишите там нужный вам Assembler code и возвращаете значения посредством функции.
Примерно так.
Это может быть и не по теме
Сделал переменную глобальной. Если выполнить только 1-ю строчку ассемблерного кода то я вижу сообщение которое запрограммировал в функции обработчике исключений. Если 2-ю то получаю Access violation. Если 2-ю и 3-ю то Access violation и процесс уже не может после этого работать. В студийном отладчике при этом везде вопросики и я не знаю что это значит(ну идут адреса, а рядом с ними вот так - ??????). 3-я строчка отдельно работает без всяких напрягов.
В ассемблере не шарю но во всех материалах которые мне попадались код такой или примерно такой. Но в любом случае ни один не работает
Privileged instruction.
Раз компилятор молчит, вот здесь может и собака и зарыта.
Давайте так Вы пишите 1-ю строчку ассемблерного кода:
Это так
{
handler = (_except_handler);
C++ Builder - Не управляемая платформа не в обиду будет сказано (Я с Builder C++ как черт из табакерки у Builder нормальна только JAVA - это мой выбор)
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
SYSTEM_INFO SI;
LPVOID MemAddr;
DWORD _memaddr, Curr_SEH;
DWORD handler;
EXCEPTION_DISPOSITION __cdecl _except_handler(_EXCEPTION_RECORD * ExceptionRecord, LPVOID EstablisherFrame, _CONTEXT * ContextRecord, LPVOID DispatcherContext)
{
ShowMessage("111");
// Изменяем значение регистра EAX в context record таким образом, чтобы оно
// указывало на какое-либо, доступное для записи место в памяти.
// ContextRecord->Eax = (DWORD)&scratch;
// Просим ОС еще раз попытаться выполнить вызвавшую исключение инструкцию.
return ExceptionContinueExecution;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Memo1->Clear();
GetSystemInfo(&SI);
MemAddr = VirtualAlloc(NULL, SI.dwPageSize * 10, MEM_COMMIT, PAGE_READWRITE);
_memaddr = DWORD(MemAddr);
Edit1->Text = IntToHex(int(_memaddr), 8);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
*(PDWORD)_memaddr = 1; // Преднамеренно вызываем исключение
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
handler = (_except_handler); // вот эта строчка не канает, пояснения ниже
__asm {
push handler
// push FS:[0]
// mov FS:[0], ESP
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
DWORD lpflOldProtect;
VirtualProtect(MemAddr, SI.dwPageSize * 10, PAGE_READONLY, &lpflOldProtect);
}
//---------------------------------------------------------------------------
[BCC32 Error] Unit1.cpp(61): E2034 Cannot convert '_EXCEPTION_DISPOSITION (*)(_EXCEPTION_RECORD *,void *,_CONTEXT *,void *)' to 'unsigned long'
Full parser context
Unit1.cpp(60): parsing: void _fastcall TForm1::Button1Click(TObject *)
Насчёт буилдера не могу ничего сказать т.к. использую иключительно делфи. так что возможно что вы правы на все 110%
Не очень понимаю концепцию программы
Суть программы в том чтобы перехватывать запись по определённым адресам. Для этого я планирую поставить этому региону атрибут PAGE_NOACCESS, и в подменённой функции обработчике ошибок типа Access violation менять его обратно на PAGE_READWRITE, возвращать ExceptionContinueExecution для того чтоб процесс всётаки записал данные. Вот собственно и весь замысел.
Если у вас есть какие нибудь идеи по этому поводу можете поделиться, буду только рад. Но пока это видится чуть ли не единственным решением.
Сёдня и завтра буду обмывать новую машину купленную другом, по этому не смогу быстро реагировать на сообщения.
Но тема для меня очень важная, Это некая "точка останова" в написании программы :)
Если ваш exe-файл не связал с какой-то игрой(но это не факт), то его можно запустить через IDA. В IDA можно увидеть Assembler code который можно потом вставить в вашу программу.
Пока больше не могу на это тратить время(и ваше не хотел бы), и вопрос можно считать закрытым.
В профессиональном программировании надо избегать такие инструкции как бесконечный цикл.
Это может работать на вашем компе, а на другом просто "зависнет".
Для этого есть пользовательские события.
А проблема как раз в том что я не смог заполучить событие.
А IDA как вообще может помоч? Там адреса по которым нужно считывать всегда разные. Ну т.е. открывается окно и программа выводит данные полученые из интернет в окно, и за одно заполняет эту строку(которую я читаю). Закрываем\открываем окно и адрес строки другой.
Я может просто не понимаю вашу идею, если не сильно обременит прокоментируйте по подробней. Какой ассемблер код нужно извлеч, куда вставить, и т.д.
Из интернета тут IDA не при делах (хотя ?)
Если exe-файл выходит в NET, если я не ошибаюсь можно тоже отследить.
Насчет адресов они всегда будут разные при любых условиях.
Вот об этом и стоит говорить будем голову ломать двоём.
Не бывает события которые программисты не придумали.
Правда скажу до next выводных.
Не знаю, почему с телефона, не могу ответь.
Напишите на Личную Почту:
Что и как и как вам надо. Так проще и без дураков или полет на пальцах.
Там не так всё просто. Там идёт передача пакетами зашифрованными, т.е. нет информации для какого окна пришли данные
На момент когда я задавал вопрос я просто не знал что мне нужно работатиь с VEH. VEH оказался куда более мощьным механизмом работы с исключениями. Вот прстой пример на делфи как обрабатывать исключения глобально для всего процесса:
Данный пример демонстрирует перехват Access violation.
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
function AddVectoredExceptionHandler(FirstHandler: CARDINAL; VectoredHandler: POINTER): POINTER; stdcall; external 'Kernel32.dll' name 'AddVectoredExceptionHandler';
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
PEXCEPTION_RECORD = ^EXCEPTION_RECORD;
EXCEPTION_RECORD = packed record
ExceptionCode: CARDINAL;
ExceptionFlags: CARDINAL;
ExceptionRecord: PEXCEPTION_RECORD;
ExceptionAddress: POINTER;
NumberParameters: CARDINAL;
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: POINTER;
lpflOldProtect: CARDINAL;
implementation
{$R *.dfm}
// ОБРАБОТЧИК ИСКЛЮЧЕНИЙ ПОВЕРХ СИСТЕМНОГО
function MyVectoredHandler(ExceptionInfo: PEXCEPTION_POINTERS): INTEGER; stdcall;
begin
if ExceptionInfo.ExceptionRecord.ExceptionCode = EXCEPTION_ACCESS_VIOLATION then
begin
ShowMessage('Произошло исключение. ExceptionCode = EXCEPTION_ACCESS_VIOLATION');
VirtualProtect(MemAddr, SI.dwPageSize * 10, PAGE_READWRITE, @lpflOldProtect);
result := EXCEPTION_CONTINUE_EXECUTION;
end
else
result := EXCEPTION_CONTINUE_SEARCH;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
PrevHandler: POINTER;
begin
PrevHandler := AddVectoredExceptionHandler(CALL_FIRST, Addr(MyVectoredHandler));
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
VirtualProtect(MemAddr, SI.dwPageSize * 10, PAGE_READONLY, Addr(lpflOldProtect));
end;
// КНОПКА ВЫЗЫВАЮЩАЯ ИСКЛЮЧЕНИЕ
procedure TForm1.Button3Click(Sender: TObject);
var
A: PAnsiChar;
begin
A := MemAddr;
A^ := 'S';
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Clear;
GetSystemInfo(SI);
MemAddr := VirtualAlloc(NIL, SI.dwPageSize * 10, MEM_COMMIT, PAGE_READWRITE);
Edit1.Text := IntToHex(CARDINAL(MemAddr), 8);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
VirtualFree(MemAddr, SI.dwPageSize * 10, 0);
end;
end.
Не вздумайте лепить этот код куда попало. Если не вы вызываете Access violation, то перехватывать его бессмыслено, всё равно либо сообщение об ощибке, либо разрушение процесса(если вы в этом обработчике сообщите что исключение обработано)
Одно давно(1.02.2013), а одно вчера(15,03,2013)
Не могу понять в чем проблема.
Появилась пару-треек месяцев назад.
У меня есть проблемы я не могу зайти на этот сайт с телефона(точнее на определенные ветки, если точнее ветка форум)
Например выбираю ветку "Общалка"
Выдаёт древо тем, а вот ветку выбрать не могу пишет СТРАНИЦА не найдена или удалена и всякую лабудень.
Раньше работала.
Думаю есть не адекватный Java-скрипт для Android
Сейчас можете писать? Почта к сожалению для меня не очень удобна. Всё открывается по пол часа, с курсором что якобы грузится, при этом индикаторы интернет подключения не горят. Сообщение отправляю, а мне пишут что надо выбрать хотябы одного кому отправлять, при этом всё заполненно. Не знаю как у других, но лично у меня на этом сайте проблемы с почтой.
Может в настройках браузера что не так, но я не собираюсь их менять ради одного сайта.
Если писать можете давайте тут переписываться