Текущий архив: 2007.10.07;
Скачать: CL | DM;
Вниз
Изменить VMT Найти похожие ветки
← →
DevilDevil © (2007-07-23 10:20) [0]Как бы то ни было странно, пишу такую функцию, типа PatchSomeClass(C : TClass) в теле которой происходит "подмена" адреса одной виртуальной функции.
Как я себе это представляю.
Для каждого класса существует некий массив указателей на функции (VMT). В каждом экземпляре такого класса хранится указатель на массив-VMT. Следовательно, получив указатель на VMT, зная смещение, я могу записать в этот массив произвольный указатель на функцию.
Все мои опыты приводят к AccessViolation. Есть ли какие нибудь предположения или наработки по данному поводу?
← →
umbra © (2007-07-23 10:23) [1]
> Есть ли какие нибудь предположения
неправильно, не то или не туда записываете :)
← →
Юрий Зотов © (2007-07-23 10:23) [2]Мысль правильная. Видимо, ошибка в коде.
← →
DevilDevil © (2007-07-23 10:36) [3]не приведёте на ваш взгляд правильный код?
← →
umbra © (2007-07-23 10:42) [4]не приведёте на ваш взгляд правильный код? :)
← →
DevilDevil © (2007-07-23 11:06) [5]ну допустим так:
procedure PatchSomeClass(C : TClass; Offset : integer; Proc : pointer);
var
P : pinteger;
begin
P := pinteger(@C); // получить указатель на данные класса
P := Pointer(P^); // получить указатель на VMT
P := pointer(integer(P) + Offset); // получить указатель на данные в VMT
P^ := integer(Proc);
end;
<-- это я только что написал, не тестировал. Но, по-моему, так должно быть верно.
← →
Сергей М. © (2007-07-23 11:15) [6]
> Все мои опыты приводят к AccessViolation
И правильно приводят, потому что
http://www.delphikingdom.com/asp/answer.asp?IDAnswer=46314
(см. пост 30-10-2006 10:21)
← →
DevilDevil © (2007-07-23 11:38) [7]В таком случае... есть ли у кого-нибудь информация хорошая по VirtualProtect, WriteProcessMemory и FlushInstructionCache ?
← →
umbra © (2007-07-23 11:50) [8]так по ссылке же в каком-то посте написано, что в Jedi это уже есть. Скачайте и посмотрите.
← →
DevilDevil © (2007-07-23 11:56) [9]ну да, да... кроме этого этвета я ещё ожидал "см. хелп". :)
Оно понятно. Но если кто-то уже сталкивался с проблемой и успешно её решил, пусть поделится 5ю строками. Иначе постараюсь найти в Jedi.
За оказанную помощь, спасибо!
← →
Сергей М. © (2007-07-23 12:10) [10]
> есть ли у кого-нибудь информация хорошая по VirtualProtect,
> WriteProcessMemory и FlushInstructionCache ?
Что тебе непонятно в их использовании ?
← →
Инс © (2007-07-23 13:07) [11]
> Как бы то ни было странно, пишу такую функцию, типа PatchSomeClass(C
> : TClass) в теле которой происходит "подмена" адреса одной
> виртуальной функции.
Только эта ваша функция на других версиях Delphi может не работать.
← →
DevilDevil © (2007-07-23 13:51) [12]теоретически - да.
Но каждая версия Delphi поддерживает asm-макрос VMTOFFSET. Поэтому должно получиться.
← →
umbra © (2007-07-23 14:29) [13]
> Только эта ваша функция на других версиях Delphi может не
> работать
если обращаться только по неотрицательным смещениям в вмт, то должна работать во всех версиях, где можно создавать СОМ-объекты
← →
Инс © (2007-07-23 14:41) [14]Это я к чему... Если планируется таким образом подменить в VMT ссылку на конкретный метод конкретного класса, а в будущих версиях структура этого класса изменится и адрес метода окажется по другому смещению, то можно нарваться на неприятность. Хотя допускаю, что если не использовать непосредственно цифровые значения смещений, то может и получится.
← →
DevilDevil © (2007-07-23 15:04) [15]вообще хочется "подменить" методы BeforeDestucturing и AfterConstuction <-- как это очень похоже они называются. Их смещения отрицательные. Вряд ли сменятся.
← →
Сергей М. © (2007-07-23 15:06) [16]
> вообще хочется "подменить" методы BeforeDestucturing и AfterConstuction
А с чем связано рождение этой блажи ?
← →
Инс © (2007-07-23 15:29) [17]
> BeforeDestucturing и AfterConstuction
Я таких не знаю ;)
А если серьезно, то у меня такое подозрение, что Вы просто неверно спроектировали структуру классов, вот теперь и изворачиваетесь. Может просто пересмотреть структуру?
← →
Игорь Шевченко © (2007-07-23 15:31) [18]
> вообще хочется "подменить" методы BeforeDestucturing и AfterConstuction
> <-- как это очень похоже они называются. Их смещения отрицательные.
> Вряд ли сменятся.
А переопределить методы в наследниках что мешает ? Они же виртуальные.
← →
oxffff © (2007-07-23 15:50) [19]Сейчас тебе пример напишу. :)
← →
oxffff © (2007-07-23 15:55) [20]var
Form1: TForm1;
Old:Pointer;
implementation
uses Math;
{$R *.dfm}
procedure Myproc(Obj:Tobject);
var a:string;
begin
a:=obj.ClassName;
Messagebox(0,pchar(A),pchar(A),0);
asm
call old;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var ClassType:TClass;
a:pointer;
OldFlags:DWORD;
begin
ClassType:=Tbutton;
VirtualProtect(ClassType,4096,PAGE_EXECUTE_READWRITE,OldFlags);
a:=@Myproc;
asm
push eax;
push ebx;
mov eax,a;
mov ebx,ClassType;
lea ebx,[ebx-$1C];
xchg [ebx],eax;
mov old,eax;
pop ebx;
pop eax;
end;
FlushInstructionCache(HInstance,nil,0);
with TButton.Create(nil) do parent:=self;
end;
← →
oxffff © (2007-07-23 16:03) [21]Поправь на
procedure Myproc(Obj:Tobject);
var a:string;
begin
a:=obj.ClassName;
Messagebox(0,pchar(A),pchar(A),0);
asm
mov eax,obj;
call old;
end;
end;
← →
DevilDevil © (2007-07-23 17:00) [22]oxffff, круто, попробую сегодня!
> Сергей М. © (23.07.07 15:06) [16]
> Инс © (23.07.07 15:29) [17]
> Игорь Шевченко © (23.07.07 15:31) [18]
Ну... как сказать...
Хочется мне сделать некий менеджер объектов классов, которые во-первых, в случае чего будут сами удаляться (finalization), во-вторых, которые можно было бы удалить всего одной функцией.
Многие сейчас захотят сказать "наследуйся от интерфейса"... но это не совсем то, что мне нужно.
Для этого был создан мой класс, вышеупомянутые методы которого используются для добавления и удаления себя из буффера объектов.
Для того, чтобы "воспользоваться" таким классом нужно просто пронаследовать новый класс от этого.
Но, чтобы модуль был полноценным, хочу написать такую функцию, которая могла бы пропатчить не просто экземпляр класс, а целый класс. К примеру, если я буду писать компонент с такой особенностью, то я вроде бы не смогу пронаследовать его одновременно от 2х классов: от TComponent и моего класса. Ну или нужно "пропатчить" имеющийся класc, TStream, например.
Реальной какой-то пользы от такой функции я не жду ... , но:
1) интересно написать такую функцию
2) она может понадобиться
← →
Сергей М. © (2007-07-23 17:03) [23]
> объектов .. которые во-первых, в случае чего
> будут сами удаляться
Это как это ?
← →
umbra © (2007-07-23 17:26) [24]О! Множественное наследование в Делфи. Это круто.
← →
Rouse_ © (2007-07-23 17:45) [25]Мошт тебе на 2007-ую перейти, там хелперы для расширения возможностей базовых классов есть...
← →
DevilDevil © (2007-07-23 17:45) [26]> Сергей М. © (23.07.07 17:03) [23]
представь глобальную переменную - интерфейс. Если ты её не удалишь, она сама удалится.
А вот если ты разрабатываешь класс-текстуру, то все объекты этого класса нужно будет удалить прежде, чем будет удалён контекст устройства.
> umbra © (23.07.07 17:26) [24]
Попробуй наследоваться, скажем, от TComponent и TStream
← →
DevilDevil © (2007-07-23 17:46) [27]> Rouse_ © (23.07.07 17:45) [25]
да боюсь я пока на новые версии переходить.
и так справлюсь. :)
← →
oxffff © (2007-07-23 18:33) [28]
> Хочется мне сделать некий менеджер объектов классов, которые
> во-первых, в случае чего будут сами удаляться (finalization),
> во-вторых, которые можно было бы удалить всего одной функцией.
>
Так финализация или удаление?
>Для этого был создан мой класс, вышеупомянутые методы которого >используются для добавления и удаления себя из буффера объектов.
Newinstance и FreeInstance?
← →
Инс © (2007-07-23 19:11) [29]Из-за неправильного употребления Вами терминов я ничего не понял:
> в случае чего будут сами удаляться (finalization)...
> во-вторых, которые можно было бы удалить всего одной функцией....
Кто удаляться? Классы или экземпляры классов? Если второе, то они и так удаляются вызовом одного метода - Free. А интерфейсы зря недооцениваете - там вам и подобие множественного наследования (можно еще на директиву implements глянуть) и горизонтальный полиморфизм, и автоматическая финализация. Плюс действительно class helper - достаточно мощная вещь, может стоит подумать о переходе на новые версии. Но все же меня терзают смутные сомнения в целесообразности сего действия. Мне как-то всегда возможностей классического ООП хватало.
← →
DevilDevil © (2007-07-23 19:13) [30]
procedure DeleteObjects();
цикл по всем объектам
ARR[i].Free;
finalization
DeleteObjects();
Либо сам удалишь, вызвав DeleteObjects в нужный момент, либо он всё равно вызовется при finalization.
в "конструкторе" объект добавляет себя в массив
в "деструкторе" объект удаляет себя из массива
← →
Сергей М. © (2007-07-24 08:15) [31]
> DevilDevil © (23.07.07 17:45) [26]
> представь глобальную переменную - интерфейс. Если ты её
> не удалишь, она сама удалится
И что ?
← →
Инс © (2007-07-24 10:16) [32]
> Либо сам удалишь, вызвав DeleteObjects в нужный момент,
> либо он всё равно вызовется при finalization.
А какой смысл освобождать память под экземпляр при завершении приложения? Когда процесс завершается система и так освобождает всю занятую им память. Разве что если в деструкторе выполняется какое-либо сохранение данных в файл или еще что-то в этом роде. А вот с интерфейсами все интереснее - объект финализируется когда выходит за область видимости. Другими словами, память будет освобождена не просто автоматически, но еще и сразу же, как в объекте отпадет необходимость.
← →
Инс © (2007-07-24 10:59) [33]Кстати, может еще стоит посмотреть, как управление временем жизни в компонентах организовано?
← →
oxffff © (2007-07-24 11:13) [34]
> Инс © (24.07.07 10:16) [32]
>
> > Либо сам удалишь, вызвав DeleteObjects в нужный момент,
>
> > либо он всё равно вызовется при finalization.
>
>
> А какой смысл освобождать память под экземпляр при завершении
> приложения? Когда процесс завершается система и так освобождает
> всю занятую им память. Разве что если в деструкторе выполняется
> какое-либо сохранение данных в файл или еще что-то в этом
> роде. А вот с интерфейсами все интереснее - объект финализируется
> когда выходит за область видимости. Другими словами, память
> будет освобождена не просто автоматически, но еще и сразу
> же, как в объекте отпадет необходимость.
Вот вам задача. Два объекта содержат интерфейсы друг друга.
Как правильно освободить эти объекты?
Вот пример
TABC=class(TinterfacedObject)
public
abc:IINTERFACE;
end;
procedure TForm1.Button1Click(Sender: TObject);
var a,b:TABC;
c,d:IUnknown;
begin
a:=TABC.Create;
b:=TABC.Create;
a.abc:=b;
b.abc:=a;
c:=a;
d:=b;
c:=nil;
d:=nil;
end;
После этого объекты продолжают существовать.
← →
Инс © (2007-07-24 11:21) [35]
> После этого объекты продолжают существовать.
Естественно. Счетчик ссылок был два, стал - один.
> Как правильно освободить эти объекты?
Отвязать друг от друга. Например, так:type
TABC=class(TinterfacedObject)
public
abc:IINTERFACE;
destructor Destroy; override;
end;
procedure TForm1.Button1Click(Sender: TObject);
var a,b:TABC;
c,d:IUnknown;
begin
a:=TABC.Create;
b:=TABC.Create;
a.abc:=b;
b.abc:=a;
c:=a;
d:=b;
c:=nil;
d:=nil;
b.abc:=nil; // Можно наоборот, не имеет значения
end;
{ TABC }
destructor TABC.Destroy;
begin
Application.MessageBox("11","11",0);
inherited;
end;
← →
oxffff © (2007-07-24 11:33) [36]
> b.abc:=nil; // Можно наоборот, не имеет значения
A и B не трогай.
Твое утверждение
>объект финализируется
> когда выходит за область видимости.
А если ссылок на интерфейсы (т.е c,d) нет, то объекты остануться.
ЕЖЕЛИ ты не приложишь усилий до выхода из области видимости "расцепить их". Но об этом надо задумываться!!!.
Поэтому интерфейсы это не панацея.
← →
Инс © (2007-07-24 11:43) [37]
> oxffff © (24.07.07 11:33) [36]
Не совсем понял, в чем вы меня убедить пытаетесь. Подводные камни в работе с интерфейсами безусловно есть. Тот пример что Вы привели - не единственный. Вот еще: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=759 . Естественно работая с таким механизмом нужно знать и помнить как документированные фичи, так и эти самые подводные камни. Не зная всего этого при работе с интерфейсами очень легко нарваться.
А моя фраза "объект финализируется при выходе за область видимости" шла в противовес финализации при завершении приложения, на мой взгляд практически бессмысленной в большенстве случаев.
← →
oxffff © (2007-07-24 11:52) [38]
> А моя фраза "объект финализируется при выходе за область
> видимости" шла в противовес финализации при завершении приложения,
> на мой взгляд практически бессмысленной в большенстве случаев.
>
Да я то собственно не связывал ваше и мое обсужение с темой автора.
В условий отсутствия полной и исчерпывающей информации сказать, что нужно автору темы я не представляю возможным.
Он попросил пример модификации VMT. Дали. А что дальше. Неизвестно.
← →
oxffff © (2007-07-24 11:59) [39]
> Не совсем понял, в чем вы меня убедить пытаетесь. Подводные
> камни в работе с интерфейсами безусловно есть. Тот пример
> что Вы привели - не единственный. Вот еще: http://www.delphikingdom.
> com/asp/viewitem.asp?catalogid=759 . Естественно работая
> с таким механизмом нужно знать и помнить как документированные
> фичи, так и эти самые подводные камни. Не зная всего этого
> при работе с интерфейсами очень легко нарваться.
Могу пояснить пример, который я вам привел.
Когда разрабатывали .NET было два взгляда на GC.
Один из этих вглядов разделяли COM разработчики.
Но им приводили в пример циклический список.
В итоге пошли по другому пути.
(Мое вольное повествование содержания статьи в интернете разработчиков .NET)
Поэтому я и привел вам этот пример.
← →
DevilDevil © (2007-07-24 17:09) [40]> Он попросил пример модификации VMT. Дали. А что дальше.
> Неизвестно.
Попробовать так и не успел; на днях попробую.
Ну как сказать... во-первых, просто хочется, чтобы объекты в любом случае удалялись. Во-вторых, есть такие объекты, который обязательно нужно удалить... и сделать это нужно в определённое время. Допустим вы пишите менеджер текстур; все текстуры в любом случае должны удалиться. Только сделать это они должны до удаления контекста устройства.
Как минимум, необходимость в хранении массива таких объектов есть. + Объект должен сам себя записывать в такой массив, и сам себя из него удалять.
Я хоть и не блеснул умением объяснять, надеюсь, вы хотя бы стали допускать необходимость в том механизме, который я стараюсь реализовать.
← →
Инс © (2007-07-24 17:17) [41]Все, что вы описали, элементарно делается и без пропатчивания VMT. Нужно просто хорошо продумать систему классов
← →
DevilDevil © (2007-07-24 17:46) [42]я об этом уже писал.
делается это действительно просто: создаётся базовый класс, от которого в дальнейшем наследуются все мои классы.
DevilDevil © (23.07.07 17:00) [22]
Реальной какой-то пользы от такой функции я не жду ... , но:
1) интересно написать такую функцию
2) она может понадобиться
← →
DevilDevil © (2007-07-26 10:48) [43]> oxffff © (23.07.07 15:55) [20]
Спасибо, всё работает как надо.
Если что, вот полученный модуль: http://forum.mirgames.ru/index.php?act=Attach&type=post&id=3247
Ну и если хотите пообсуждать, вот ветка:
http://forum.mirgames.ru/index.php?act=ST&f=5&t=3986&st=0#entry62664
← →
oxffff © (2007-07-26 11:21) [44]To DevilDevil © (26.07.07 10:48) [43]
lea edx, [eax + VMTOFFSET TObject.AfterConstruction] // edx - указатель на AC
add eax, VMTOFFSET TObject.BeforeDestruction // eax - указатель на BD
mov ecx, AfterConstruction
mov [edx], ecx
mov ecx, BeforeDestruction
mov [eax], ecx
А кто будет вызывать original AC, BD обработчики?
← →
DevilDevil © (2007-07-26 11:45) [45]да вот я думаю, может не заморачиваться на них?
всё равно, врядли их кто то использует. Ни в одной книге я о них не слышал.
← →
oxffff © (2007-07-26 12:25) [46]Собственно не касаясь выбора способа решения.
А как же?
TCustomForm.AfterConstruction;
TDataModule.AfterConstruction;
TCustomForm.BeforeDestruction;
TDataModule.BeforeDestruction;
TComponent.BeforeDestruction;
← →
Игорь Шевченко © (2007-07-26 12:33) [47]
> да вот я думаю, может не заморачиваться на них?
> всё равно, врядли их кто то использует.
Я использую активно. Я надеюсь, не одинок.
А вот что будет с теми, кто рассчитывает на штатное поведение, а наткнется на произведение такого изобретателя велосипеда с пятью квадратными колесами, я не берусь предположить
← →
DevilDevil © (2007-07-26 12:52) [48]мда...
Тогда нужно хранить ещё один массив записей (класс, AC, BD) ...
← →
Инс © (2007-07-26 12:57) [49]
> Тогда нужно хранить ещё один массив записей (класс, AC,
> BD) ...
Нет, просто нужно не маяться дурью а делать все по-человечески. Либо не пускать подобные фишки за границы своего личного проекта.
← →
DevilDevil © (2007-07-26 13:12) [50]эээ ?
нет, вызывать методы предка реально. Сделать это можно описанным мной выше "способом". А как это "по человечески" ?
← →
Инс © (2007-07-26 13:19) [51]
> нет, вызывать методы предка реально.
Реально - inherited. Более далекого предка - в принципе тоже реально. Побегать по VMT. Но вот только в хорошо спроецированной системе такого быть не должно. Если это требуется - значит система спроектирована плохо.
> А как это "по человечески" ?
По-человечески, это чтобы я, используя ваши юниты, не наткнулся на грабли, связанные с тем, что по неизвестным мне причинам принципы ООП не работают. В своем проекте, если что-то горит и нет времени переделывать всю структуру классов - ради бога, если работать будет. Другим же такую свинью не подсовывать.
← →
DevilDevil © (2007-07-26 13:42) [52]> Инс © (26.07.07 13:19) [51]
Вы слишком агрессивно настроены
Страницы: 1 2 вся ветка
Текущий архив: 2007.10.07;
Скачать: CL | DM;
Память: 0.62 MB
Время: 0.019 c