Есть ли способ найти исполняемый код MyAnonymousProcedure
ссылки на переменные?
Всегда есть «способ», но в этом случае сложно.
Первый анонимный метод можно рассматривать как ссылку на интерфейс с одним методом Invoke
, как объясняется Barry Kelly.
Применяя идею кода мы получаем:
procedure MethRefToProcPtr(const MethRef; var ProcPtr);
type
TVtable = array[0..3] of Pointer;
PVtable = ^TVtable;
PPVtable = ^PVtable;
begin
// 3 is offset of Invoke, after QI, AddRef, Release
TMethod(ProcPtr).Code := PPVtable(MethRef)^^[3];
end;
К сожалению, значение ProcPtr
возвращается не то, что вы, вероятно, хотите - это адрес кода заглушки, который фиксирует интерфейсную ссылку (преобразует ссылку на интерфейс к ссылке на объект) и переходит к адресу, который мы ищем. Если проследить код, на который указывает ProcPtr
вы найдете что-то вроде этого (Delphi XE, 32-бит):
add eax,-$10
jmp FooBar
и на FooBar
адрес, который вы найдете
call Foo
или
call Bar
в зависимости от текущего значения вашего анонимного метода.
Я предполагаю, что единственный способ получить адрес FooBar
- это проанализировать инструкцию ассемблера jmp
.
Вот код, который я использовал для моих экспериментов:
procedure Foo;
begin
Writeln('Foo');
end;
procedure Bar;
begin
Writeln('Bar');
end;
procedure MethRefToProcPtr(const MethRef; var ProcPtr);
type
TVtable = array[0..3] of Pointer;
PVtable = ^TVtable;
PPVtable = ^PVtable;
begin
// 3 is offset of Invoke, after QI, AddRef, Release
TMethod(ProcPtr).Code := PPVtable(MethRef)^^[3];
end;
procedure DoSomething;
var
MyAnonymousProcedure : TProc;
MyProc : procedure;
begin
//assign an anonymous procedure to a variable.
MyAnonymousProcedure := procedure
begin
Foo;
end;
// MyAnonymousProcedure(); //Call the newly assigned procedure.
MethRefToProcPtr(MyAnonymousProcedure, MyProc);
Writeln(Format('%p', [@MyProc]));
Writeln(Format('%p', [@Foo]));
MyProc;
// do the same thing again but with a different anonymous method.
MyAnonymousProcedure := procedure
begin
Bar;
end;
// MyAnonymousProcedure();
MethRefToProcPtr(MyAnonymousProcedure, MyProc);
Writeln(Format('%p', [@MyProc]));
Writeln(Format('%p', [@Bar]));
MyProc;
end;
Может быть, я жил под скалой для 20 лет, но что значит «рассчитать хэш»? Вы хотите, чтобы вы запускали исходный код для этой процедуры через какой-то алгоритм контрольной суммы? Не могли бы вы объяснить, почему. Я, конечно, открыт для изучения новых вещей, и мне любопытно. – Sam
«Вы хотите, чтобы вы запускали исходный код для этой процедуры через какой-то алгоритм контрольной суммы?» Да, точно. – Shannon
Интересно, но * почему *? (просто любопытно) – Sam