9

在 Delphi 中,如何找出 COM 方法的地址?我可以硬编码偏移量

//0 is the offset of the QueryInterface method
p := TPonterArray(pointer(SomeInterface)^)[0];

但我更喜欢使用符号名称。以下显然不起作用:

var M : TMethod;
...
M := TMethod(SomeInterface.QueryInterface);

谢谢!

4

4 回答 4

6

您可以使用vmtoffset汇编指令来获取接口方法相对于接口方法表开头的字节偏移量。看一下System.pas_IntfCast中的实现,例如:

call dword ptr [eax] + vmtoffset IInterface.QueryInterface
...
call dword ptr [eax] + vmtoffset IInterface._Release

第一个表达式加0;第二个,8。

但是,您不能参数化这些表达式。它们是编译时常量,因此您无法在运行时选择所需的方法。您需要提前表示所有可能的方法名称。

真正需要挂钩的是QueryInterface. 一旦你有了它,你就可以返回任何你想要的代理对象,它可以拦截对所有其他方法的调用。

于 2010-07-02T05:07:12.343 回答
3

我不认为德尔福支持这一点。硬编码偏移量可能是唯一可行的方法,因为编译器不会将接口方法视为符号,其值可以分配给函数指针,就像对象方法或独立函数一样。

顺便说一句,你为什么要这样做?

于 2010-07-01T17:34:11.090 回答
2

您的代码是错误的,因为接口引用不是指向接口方法表的指针,而是指向接口方法表的指针。这就是 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 的符号名称,您最好自己将它们声明为偏移常量

于 2010-07-04T15:59:20.627 回答
1

两个附加指令允许汇编代码访问动态和虚拟方法:VMTOFFSET 和 DMTINDEX。

VMTOFFSET 从虚拟方法表 (VMT) 的开头检索虚拟方法参数的虚拟方法指针表条目的偏移量(以字节为单位)。该指令需要一个完全指定的类名,并带有一个方法名作为参数(例如,TExample.VirtualMethod),或者一个接口名和一个接口方法名。

DMTINDEX 检索传递的动态方法的动态方法表索引。该指令还需要一个完全指定的类名,并以方法名作为参数,例如 TExample.DynamicMethod。要调用动态方法,请使用包含从 DMTINDEX 获得的值的 (E)SI 寄存器调用 System.@CallDynaInst。

docwiki.embarcadero.com

这里是获取所需方法指针的代码

function GetMethodPointer(const IntRef: IInterface): Pointer; assembler;
asm
  mov eax, [IntRef] 
  add eax, vmtoffset ISomeInterface.MemberMethod
  mov eax, [eax]
end;
于 2017-04-30T13:26:58.263 回答