在 Delphi 中,如何找出 COM 方法的地址?我可以硬编码偏移量
//0 is the offset of the QueryInterface method
p := TPonterArray(pointer(SomeInterface)^)[0];
但我更喜欢使用符号名称。以下显然不起作用:
var M : TMethod;
...
M := TMethod(SomeInterface.QueryInterface);
谢谢!
您可以使用vmtoffset
汇编指令来获取接口方法相对于接口方法表开头的字节偏移量。看一下System.pas_IntfCast
中的实现,例如:
call dword ptr [eax] + vmtoffset IInterface.QueryInterface
...
call dword ptr [eax] + vmtoffset IInterface._Release
第一个表达式加0;第二个,8。
但是,您不能参数化这些表达式。它们是编译时常量,因此您无法在运行时选择所需的方法。您需要提前表示所有可能的方法名称。
您真正需要挂钩的是QueryInterface
. 一旦你有了它,你就可以返回任何你想要的代理对象,它可以拦截对所有其他方法的调用。
我不认为德尔福支持这一点。硬编码偏移量可能是唯一可行的方法,因为编译器不会将接口方法视为符号,其值可以分配给函数指针,就像对象方法或独立函数一样。
顺便说一句,你为什么要这样做?
您的代码是错误的,因为接口引用不是指向接口方法表的指针,而是指向接口方法表的指针。这就是 Delphi 接口在二进制级别上实现的方式。很难说更多并指出代码中的错误,因为您没有给出可以编译的代码示例。使用以下代码将接口引用正确转换为方法指针,这个想法来自Barry Kelly 的从方法引用创建方法指针的演示:
procedure IntRefToMethPtr(const IntRef; var MethPtr; MethNo: Integer);
type
TVtable = array[0..999] of Pointer;
PVtable = ^TVtable;
PPVtable = ^PVtable;
begin
// QI=0, AddRef=1, Release=2, etc
TMethod(MethPtr).Code := PPVtable(IntRef)^^[MethNo];
TMethod(MethPtr).Data := Pointer(IntRef);
end;
如果您更喜欢 MethNo 的符号名称,您最好自己将它们声明为偏移常量
两个附加指令允许汇编代码访问动态和虚拟方法:VMTOFFSET 和 DMTINDEX。
VMTOFFSET 从虚拟方法表 (VMT) 的开头检索虚拟方法参数的虚拟方法指针表条目的偏移量(以字节为单位)。该指令需要一个完全指定的类名,并带有一个方法名作为参数(例如,TExample.VirtualMethod),或者一个接口名和一个接口方法名。
DMTINDEX 检索传递的动态方法的动态方法表索引。该指令还需要一个完全指定的类名,并以方法名作为参数,例如 TExample.DynamicMethod。要调用动态方法,请使用包含从 DMTINDEX 获得的值的 (E)SI 寄存器调用 System.@CallDynaInst。
这里是获取所需方法指针的代码
function GetMethodPointer(const IntRef: IInterface): Pointer; assembler;
asm
mov eax, [IntRef]
add eax, vmtoffset ISomeInterface.MemberMethod
mov eax, [eax]
end;