Форум: "Прочее";
Текущий архив: 2008.04.20;
Скачать: [xml.tar.bz2];
ВнизОпределение модуля, вызвавшего функцию Найти похожие ветки
← →
Пробегал... (2008-03-06 20:21) [0]Есть программа и система плагинов к ней, каждый плагин является DLL. Чтобы плагин умел работать с ядром - он экспортирует некоторые функции, которые вызывает ядро и передает ему информацию и ссылки на функции ядра, которые можно вызыать. Это уже работает так.
В некоторых случаях надо опознать какой плагин вызывает функции ядра. Сделано, что плагин сам представляется, то есть функции ядра выглядят так например:function ExecuteCommand(SrcPlugin: THandle; command: integer): integer; stdcall;
плагин соответственно сам передает SrcHandle каждый раз при вызове функций ядра. Это собственно то, что само ядро ему и сообщило, а в итоге результат вызова LoadLibrary, то есть ссылка на начало образа DLL в ВАП, как я понимаю.
И вот интересно, а можно обойтись без этого? То есть, плагин просто вызывает:function ExecuteCommand(command: integer): integer; stdcall;
а функция сама определяет по адресу возврата этот самый THandle?
Только нужен абсолютно надежный способ, с которым невозможны косяки. Какие это подводные камни несет? И как это сделать?
← →
VirEx © (2008-03-06 20:34) [1]абсолютно надежный:
record
ресурс
константа
← →
Loginov Dmitry © (2008-03-06 20:59) [2]> Какие это подводные камни несет?
Это усложняет код. Делает его непонятным. Совершенно необоснованно.
> И как это сделать?
Видимо, сравнить адрес возврата, хранимый в стэке, с результатом LoadLibrary().
← →
Пробегал... (2008-03-06 22:16) [3]VirEx © (06.03.08 20:34) [1]
абсолютно надежный:
record
ресурс
константа
ничего не понял
Loginov Dmitry © (06.03.08 20:59) [2]
Совершенно необоснованно
ну почему не обосновано:
1) облегчает жизнь плагину, не надо каждый раз передвать и вообще помнить свой instance... Хотя конечно его и легко узнать, но тем не менее.
Например, в miranda сервисные функции не запрашивают чтобы плагины передавали свой описатель при вызове. Хотя как-то он же их идентифицирует? А может конечно и нет...
2) позволяет сделать защиту, чтобы один плагин не выдал себя за другой ;) Хотя это я понимаю притянуто за уши, если плагин захочет напакостить - то уж в ВАП процесса он может наворотить что угодно.
← →
Пробегал... (2008-03-06 22:21) [4]Loginov Dmitry © (06.03.08 20:59) [2]
Видимо, сравнить адрес возврата, хранимый в стэке, с результатом LoadLibrary().
Это ты к чему написал? Даже я понимаю, что такое сравнение никогда не пройдет, LoadLibrary возвращает ссылку на начало загруженного образа, а адрес возврата содержит ссылку на адрес кода, который должен начать исполняться после этой функции.
← →
Loginov Dmitry © (2008-03-06 22:45) [5]> облегчает жизнь плагину, не надо каждый раз передвать и
> вообще помнить свой instance
а зачем его помнить? Он запоминается в hInstance.
> позволяет сделать защиту, чтобы один плагин не выдал себя
> за другой
если ты уже загрузил плагин, то что защитить хочешь? Конец света! Опоздал! ;)
> Даже я понимаю, что такое сравнение никогда не пройдет,
> LoadLibrary возвращает ссылку на начало загруженного образа,
> а адрес возврата содержит ссылку на адрес кода
Почему не пройдет? У тебя есть адрес расположения библиотеки в памяти, возвращаемый LoadLibrary. Каким-то образом определяешь, где оканчивается область кода данной библиотеки. Извлекаешь из стека адрес возврата и проверяешь, находится ли он в данном диапазоне. По-моему так. Может я не прав. Такой хренью ни разу не загонялся.
← →
Пробегал... (2008-03-07 00:22) [6]Loginov Dmitry © (06.03.08 22:45) [5]
а зачем его помнить? Он запоминается в hInstance
откуда я знаю на чем там будут плагины писать потенциально сторонние разработчики.
← →
Пробегал... (2008-03-07 00:25) [7]Loginov Dmitry © (06.03.08 22:45) [5]
Каким-то образом определяешь, где оканчивается область кода данной библиотеки. Извлекаешь из стека адрес возврата и проверяешь, находится ли он в данном диапазоне. По-моему так. Может я не прав. Такой хренью ни разу не загонялся.
хех. Да по-моему все проще ;) Определить образ по указателю - по-моему, есть для этого такая специальная WinApi функция. Ей передаешь указатель на область кода, а она возвращает описатель модуля, загруженного по этому адресу ;)
Вопрос сводится к:
1) как называется эта функция
2) как определить адрес возврата, видимо во вставке на ассемблере, а я в этом не силен
3) какие могут быть подводные камни при таком подходе автоматического определения.
← →
Loginov Dmitry © (2008-03-07 00:27) [8]> откуда я знаю на чем там будут плагины писать потенциально
> сторонние разработчики.
ну тогда это сугубо их проблемы, как хранить (как определить, и нужно ли это вообще) hInstance.
← →
Пробегал... (2008-03-07 00:54) [9]Loginov Dmitry © (07.03.08 0:27) [8]
сугубо их проблемы, как хранить (как определить, и нужно ли это вообще) hInstance
он им нужен полюбому, иначе они не вызовут функции ядра. Я сам передаю их instance при загрузке плагина. Просто стало интересно, насколько автоматический способ оправдан. Ведь видимо в miranda он используется
← →
Slym © (2008-03-07 05:00) [10]для таких случаев родная Дельфя пользует Sender:TSomeObg, иначе получается игра "Кто стукнул в спину"
← →
Rouse_ © (2008-03-07 10:42) [11]
> а функция сама определяет по адресу возврата этот самый
> THandle?
Адрес возврата будет в области памяти по которой подгружена библиотека, зная список библотек и их хэндлы - ты сможешь определить, кто сейчас дернл эту функцию...
Ну к примеру вот так:
Библиотека:library plugin;
{$R *.res}
uses
Windows,
SysUtils;
type
TExecuteCommand = function(command: integer): integer; stdcall;
procedure TestPlugin(lpParams: Pointer); stdcall;
var
ExecuteCommand: TExecuteCommand;
I: Integer;
SleepTime: DWORD;
begin
Randomize;
@ExecuteCommand := GetProcAddress(GetModuleHandle(nil), "ExecuteCommand");
if not Assigned(@ExecuteCommand) then
raise Exception.Create("Ошибка определения адреса функции ядра.");
for I := 0 to 9 do
begin
SleepTime := Random(4) * 1000;
Sleep(SleepTime);
ExecuteCommand(I);
end;
end;
var
Dumme: THandle;
begin
CreateThread(nil, 0, @TestPlugin, nil, 0, Dumme);
end.
Приложение:unit uEngine;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TPluginInfo = record
PluginNage: String;
PluginHandle: THandle;
PluginSize: Int64;
end;
TEngineDlg = class(TForm)
memLog: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
public
Plugins: array of TPluginInfo;
procedure LoadPlugins;
procedure ReleasePlugins;
procedure Log(const Value: String);
end;
var
EngineDlg: TEngineDlg;
RTL: TRTLCriticalSection;
implementation
{$R *.dfm}
function ExecuteCommand(command: integer): integer; stdcall;
var
CallAddr: DWORD;
I: Integer;
Founded: Boolean;
begin
EnterCriticalSection(RTL);
try
asm
mov eax, [esp + $4C];
mov CallAddr, eax
end;
Founded := False;
for I := 0 to Length(EngineDlg.Plugins) - 1 do
if (CallAddr > EngineDlg.Plugins[I].PluginHandle) and
(CallAddr < EngineDlg.Plugins[I].PluginHandle +
EngineDlg.Plugins[I].PluginSize) then
begin
Founded := True;
EngineDlg.Log(Format(
"Был произведен вызов функции ядра из библиотеки %s, параметр %d",
[EngineDlg.Plugins[I].PluginNage, command]));
Break;
end;
if not Founded then
EngineDlg.Log(Format(
"Был произведен вызов функции ядра из неизвестной библиотеки," +
" адрес возврата %x, параметр %d",
[CallAddr, command]));
finally
LeaveCriticalSection(RTL);
end;
end;
exports
ExecuteCommand;
{ TEngineDlg }
procedure TEngineDlg.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ReleasePlugins;
end;
procedure TEngineDlg.FormCreate(Sender: TObject);
begin
LoadPlugins;
end;
procedure TEngineDlg.LoadPlugins;
var
SR: TSearchRec;
Len: Integer;
Path: String;
begin
Len := 0;
Path := ExtractFilePath(ParamStr(0));
if FindFirst(Path + "*.dll", faAnyFile, SR) = 0 then
try
repeat
Inc(Len);
SetLength(Plugins, Len);
Plugins[Len - 1].PluginNage := SR.Name;
Plugins[Len - 1].PluginHandle := LoadLibrary(PChar(Path + SR.Name));
Plugins[Len - 1].PluginSize := SR.Size;
Log("Загружена библиотека: " + SR.Name);
until FindNext(SR) <> 0;
finally
FindClose(SR);
end;
end;
procedure TEngineDlg.Log(const Value: String);
begin
memLog.Lines.Add(TimeToStr(Now) + ": " + Value);
end;
procedure TEngineDlg.ReleasePlugins;
var
I: Integer;
begin
for I := 0 to Length(Plugins) - 1 do
FreeLibrary(Plugins[I].PluginHandle);
end;
initialization
InitializeCriticalSection(RTL);
finalization
DeleteCriticalSection(RTL);
end.
← →
Игорь Шевченко © (2008-03-07 11:07) [12]Кулибины
← →
www (2008-03-07 11:47) [13]
> в miranda сервисные функции не запрашивают чтобы плагины
> передавали свой описатель при вызове. Хотя как-то он же
> их идентифицирует?
исходники есть, смотри
← →
Сергей М. © (2008-03-07 11:56) [14]
> 1) как называется эта функция
FindHInstance
> 2) как определить адрес возврата
Он нафих не нужен.
procedure Dummy;
begin
end;
..
MyResult := ExecuteCommand(FindHInstance(@Dummy); SomeCommand);
← →
Пробегал2... (2008-03-07 12:43) [15]Rouse_ © (07.03.08 10:42) [11]
ну идея понятна. Начало образа в ВАП мы знаем, прибавляем к нему размер библиотеки - и получаем конец... А это точно справедливо? Если на диске библиотека занимает 50 тысяч байт, она в памяти процесса тоже будет занимать ровно 50 тысяч байт?
Но видишь кстати есть способ проще мне кажется: FindHInstance
Игорь Шевченко © (07.03.08 11:07) [12]
Кулибины
типа "вы все делаете неправильно, а я знаю как правильно, но не скажу". К чему такие посты, Игорь? А потом обижаетесь, что вам хамят.
Сергей М. © (07.03.08 11:56) [14]
FindHInstance
да, точно... Спасибо!
Сергей М. © (07.03.08 11:56) [14]
MyResult := ExecuteCommand(FindHInstance(@Dummy); SomeCommand);
а что такое ExecuteCommand?
← →
Пробегал2... (2008-03-07 12:46) [16]а-а-а... Это ты взял функцию из поста Rouse_...
Ну теперь все ясно. Функция называется FindHInstance, сам код получения адреса возврата я так понимаю:asm
mov eax, [esp + $4C];
mov CallAddr, eax
end;
Это для функции с одним параметром? А если функция с двумя параметрами или тремя?
И осталось выяснить - несет ли это в себе какие подводные камни?
← →
Сергей М. © (2008-03-07 12:47) [17]
> что такое ExecuteCommand?
Как это что ?
Та самая "функция ядра", о которой ты завел речь в самом первом своем посте)
← →
Сергей М. © (2008-03-07 12:49) [18]
> Пробегал2... (07.03.08 12:46) [16]
>
> а-а-а... Это ты взял функцию из поста Rouse
Пробегай помедленее, мож и в своем посте увидишь)
← →
Игорь Шевченко © (2008-03-07 12:59) [19]Пробегал2... (07.03.08 12:43) [15]
Когда коту нечего делать, он делает известно что. Мне непонятно желание странного - идентификация чего-либо через косвенные анальные отверстия, вместо явной идентификации.
← →
Пробегал2... (2008-03-07 13:05) [20]Сергей М. © (07.03.08 12:47) [17]
Как это что ?
Та самая "функция ядра", о которой ты завел речь в самом первом своем посте)
а... Теперь понял, что ты не понял ;)
А откуда ты тогда взял адрес функции Dummy? Да и что это за функция?
Есть ядро. Есть плагин в виде DLL. Ядро загружает плагин функцией LoadLibrary и передает ему адрес некоторых системных функций, с которым плагин и работает.
Плагин из любого места своего кода может вызвать эти функции. Они вызовутся, а дальше что? Откуда ядро знает КТО вызвал эту функцию? Ведь адрес этой функции известен многим плагинам. Поэтому адрес возврата нужено определять.
← →
Пробегал2... (2008-03-07 13:06) [21]Игорь Шевченко © (07.03.08 12:59) [19]
Мне непонятно желание странного - идентификация чего-либо через косвенные анальные отверстия
а, ну да, я тоже думаю оставить свой первый вариант с явным указанием instance. Просто интересно почему разработчики Miranda (люди не дураки уверен) сделали по-другому, может я чего не понимаю... ПОэтому и стал спрашивать.
← →
oxffff © (2008-03-07 13:10) [22]GetModuleHandle и GetModuleInformation?
← →
oxffff © (2008-03-07 13:14) [23]mov eax,[ebp+04]; Адрес возврата при наличии Stack frames
← →
oxffff © (2008-03-07 13:15) [24]function ExecuteCommand(command: integer): integer; stdcall;
begin
mov eax,[ebp+04];
Далее FindHinstance предложенный Сергей М. либо [22]
. И все!!!!!!!! :))))))))))
end;
← →
Сергей М. © (2008-03-07 13:17) [25]
> Пробегал2... (07.03.08 13:05) [20]
> Теперь понял, что ты не понял
Я-то как раз понял)
> откуда ты тогда взял адрес функции Dummy?
От барана)
"Барана" перед Dummy видишь ? Вот отттуда и взял.
> и что это за функция?
По барабану что за функция.
В кач-ве Dummy можешь взять любую (в области видимости) регулярную процедуру или функцию, объявленную где-либо в проекте плагина.
> Откуда ядро знает КТО вызвал эту функцию?
Если под "КТО" подразумевается уникальное значение hInstance плагина, то плагин сам определит его определит (см. мой пример) и передаст в кач-ве первого параметра (см. твой первый пост).
Нафих при этом тебе сдались эти "адреса возврата" - ума не приложу. Потому, imho, в [19] совершенно правильная критика.
← →
Сергей М. © (2008-03-07 13:24) [26]
> почему разработчики Miranda (люди не дураки уверен) сделали
> по-другому
Разработчики делфи тоже не дураки, однако параметр Sender, заметь, у них фигурирует чуть ли не в любом обработчике любого события.
← →
Игорь Шевченко © (2008-03-07 13:32) [27]
> function ExecuteCommand(command: integer): integer; stdcall;
>
> begin
> mov eax,[ebp+04];
Все бы хорошо, но есть гарантия, что у функции ВСЕГДА будет сгенерирован стандартный пролог ?
← →
oxffff © (2008-03-07 14:24) [28]
> Игорь Шевченко © (07.03.08 13:32) [27]
Я же написал, что для этого трюка необходима генерация стекового фрейма.
А если вы посмотрите генерируется всегда если есть например managed переменные. И функция сервера не пустая.
Так что мой трюк должен работать.
← →
VirEx © (2008-03-07 18:30) [29]
> [3] Пробегал... (06.03.08 22:16)
> VirEx © (06.03.08 20:34) [1]
> абсолютно надежный:
> record
> ресурс
> константа
>
> ничего не понял
А чего не понятного?
1. recordtype
Есть минусы, например и плагин и ядро должны иметь одинаковый TInitPlug
TInitPlag=record
Name:Pchar;
Version:integer;
end;
var
p:TInitPlug;
begin
h:=LoadLibrary();
foo:=GetProcAddress(h,"InitPlugin");
if Assigned(foo) then
p.Name:=StrAlloc(1024);
foo(p);
в "p" теперь информация о плагине
else это не плагин вобще
В длл
InitPlugin(var PlugInfo:TInitPlug);
begin
PlugInfo.Name:=
PlugInfo.Version:=
2. ресурс с именем и версией плагина запихиваем в длл, в ядре загружаем данные ресурсы
3. в длл делаем константу (или в асме как-то делается) с именем и версией, ядро ищет эту константу как строку.
но это метод экстремалов :)
← →
VirEx © (2008-03-07 18:40) [30]
> [29] VirEx © (07.03.08 18:30)
begin end забыл
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2008.04.20;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.047 c