In Delphi, how do I find out the the address of a COM method?
I can hardcode the offsets
//0 is the offset of the QueryInterface method
p := TPonterArray(pointer(SomeInterface)^)[0];
but I would prefer to use symbolic names. The folllowing obviously does not work:
var M : TMethod;
...
M := TMethod(SomeInterface.QueryInterface);
Thanks!
You can use the vmtoffset assembler directive to get the byte offset of an interface method relative to the start of the interface's method table. Take a look at the implementation of _IntfCast in System.pas, for example:
call dword ptr [eax] + vmtoffset IInterface.QueryInterface
...
call dword ptr [eax] + vmtoffset IInterface._Release
The first expression adds 0; the second, 8.
You cannot parameterize those expressions, though. They're compile-time constants, so you cannot choose which method you want at run time. You need to have all possible method names represented in advance.
All you really need to hook is QueryInterface. Once you have that, you can return whatever proxy object you want that can intercept calls to all the other methods.
I don't think Delphi supports that. Hardcoding the offsets is probably the only thing that will work, since the compiler doesn't count interface methods as symbols whose value can be assigned to a function pointer, the way object methods or standalone functions can.
Why are you trying to do this, BTW?
Your code is wrong because an interface reference is not a pointer to an interface method table but a pointer to pointer to an interface method table. That is how Delphi interfaces are implemented on binary level. It is hard to say more and point out to the error in your code because you have not given a code example that can be compiled. Use the following code to convert interface reference to method pointer correctly, the idea was taken from Barry Kelly's demonstration of creating a method pointer from a method reference:
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;
If you prefer symbolic names for MethNo you are better to declare them yourself as offset constants
Two additional directives allow assembly code to access dynamic and
virtual methods: VMTOFFSET and DMTINDEX.
VMTOFFSET retrieves the offset in bytes of the virtual method pointer
table entry of the virtual method argument from the beginning of the
virtual method table (VMT). This directive needs a fully specified
class name with a method name as a parameter (for example,
TExample.VirtualMethod), or an interface name and an interface method
name.
DMTINDEX retrieves the dynamic method table index of the passed
dynamic method. This directive also needs a fully specified class name
with a method name as a parameter, for example,
TExample.DynamicMethod. To invoke the dynamic method, call
System.#CallDynaInst with the (E)SI register containing the value
obtained from DMTINDEX.
docwiki.embarcadero.com
Here the code to get the needed method pointer
function GetMethodPointer(const IntRef: IInterface): Pointer; assembler;
asm
mov eax, [IntRef]
add eax, vmtoffset ISomeInterface.MemberMethod
mov eax, [eax]
end;
Related
Hello using code below to call a function with asm and after call read the result. That works fine. Now,- how to read the argument changes afterwards, best regards
//push arguments:
for i:=lst.cnt downto 0 do begin //reverse order
ia:=longword(lst.fList^[i]);
asm push ia end; //push 32-Bit argument
end;
asm
call proc //call the routine
mov ia, eax //get result right after the call
end;
//how to read variable arguments here ?
edit:
The initial code has run for some time without any issues, even when using the loop. The reason for this question came, when i had to call a winapi routine like this:
function GetWindowRect(hWnd: HWND; var lpRect: TRect): BOOL; stdcall;
external user32 name 'GetWindowRect';
It has declared a variable record argument "lpRect" (size: 16 bytes). I was trying to (push) these 4 integers before call, and then read them after call. Turns out just passing a pointer to the data actually worked in this case.
Conclusion: So there is no such thing variable arguments, only pointers to value or record. Thanks for any inputs helped getting to this conclusion
If you pass the parameters by value, then list.fList^[i] contains the pointer to the value.
Just unreference and use it, for instance PInteger(list.fList^[i])^ for an integer parameter passed by reference (as var).
But note that your code is pretty awful, and using push within the loop is very risky. It would also need to follow the calling convention - a proc function defined with default Delphi register passes its first parameters into eax/ecx/edx. Check this reference material - your question seems to indicate that you are a bit confused with how it works.
In Delphi, how do I find out the the address of a COM method?
I can hardcode the offsets
//0 is the offset of the QueryInterface method
p := TPonterArray(pointer(SomeInterface)^)[0];
but I would prefer to use symbolic names. The folllowing obviously does not work:
var M : TMethod;
...
M := TMethod(SomeInterface.QueryInterface);
Thanks!
You can use the vmtoffset assembler directive to get the byte offset of an interface method relative to the start of the interface's method table. Take a look at the implementation of _IntfCast in System.pas, for example:
call dword ptr [eax] + vmtoffset IInterface.QueryInterface
...
call dword ptr [eax] + vmtoffset IInterface._Release
The first expression adds 0; the second, 8.
You cannot parameterize those expressions, though. They're compile-time constants, so you cannot choose which method you want at run time. You need to have all possible method names represented in advance.
All you really need to hook is QueryInterface. Once you have that, you can return whatever proxy object you want that can intercept calls to all the other methods.
I don't think Delphi supports that. Hardcoding the offsets is probably the only thing that will work, since the compiler doesn't count interface methods as symbols whose value can be assigned to a function pointer, the way object methods or standalone functions can.
Why are you trying to do this, BTW?
Your code is wrong because an interface reference is not a pointer to an interface method table but a pointer to pointer to an interface method table. That is how Delphi interfaces are implemented on binary level. It is hard to say more and point out to the error in your code because you have not given a code example that can be compiled. Use the following code to convert interface reference to method pointer correctly, the idea was taken from Barry Kelly's demonstration of creating a method pointer from a method reference:
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;
If you prefer symbolic names for MethNo you are better to declare them yourself as offset constants
Two additional directives allow assembly code to access dynamic and
virtual methods: VMTOFFSET and DMTINDEX.
VMTOFFSET retrieves the offset in bytes of the virtual method pointer
table entry of the virtual method argument from the beginning of the
virtual method table (VMT). This directive needs a fully specified
class name with a method name as a parameter (for example,
TExample.VirtualMethod), or an interface name and an interface method
name.
DMTINDEX retrieves the dynamic method table index of the passed
dynamic method. This directive also needs a fully specified class name
with a method name as a parameter, for example,
TExample.DynamicMethod. To invoke the dynamic method, call
System.#CallDynaInst with the (E)SI register containing the value
obtained from DMTINDEX.
docwiki.embarcadero.com
Here the code to get the needed method pointer
function GetMethodPointer(const IntRef: IInterface): Pointer; assembler;
asm
mov eax, [IntRef]
add eax, vmtoffset ISomeInterface.MemberMethod
mov eax, [eax]
end;
Testing this code:
procedure fii(i:integer);
var
Hbar: Thandle;
Foo: procedure (X: Integer); //i removed the stdcall here!
begin
Hbar := LoadLibrary('BAR.DLL');
if Hbar >= 32 then { success }
begin
Foo := GetProcAddress(HBar, 'FOO');
...
Foo(i); // if we debug trace this to the call of the dll we get not desired value
...
FreeLibrary(HBar);
end
else
MessageDlg('Error: could not find BAR.DLL', mtError, [mbOk], 0)
end.
What will happen if we dropped the stdcall in 32 bit or 64 bit ?
The answer is , the value $18f2dc passed into x. If its a string, it will point to position of $18f2dc ,and try to extract the string garbage from there.
This happens because Delphi just pass Pointer(s) in the code.
It could changed from run to run and not be $18f2dc, but its a 3 byte that are passed. (if you pass int its $18f2dc in decimal 1635036).
Does this number has a unique meaning?
Why is stdcall needed?
What will happen if we dropped the stdcall in 32 bit?
When no calling convention is specified, then the default of register is used. Since this does not match the true calling convention, then garbage will be passed in the parameters.
In this particular case, the function that you call expects the parameters to be passed on the stack. The function will therefore read an integer from the stack. On the other hand, the calling code assumes register calling convention and puts the argument in the EAX register. Because the calling code did not push the argument onto the stack, the function gets what just happens to be on the stack when the function is called.
To be honest, there's not really much point in trying to reasons about ABI(Application Binary Interface - the interface between two program modules) mismatches like this. You would really try to reason about what would happen if you declared a different number of arguments on each side of the interop(Interoperability - property of a product or system, whose interfaces are completely understood, to work with other products or systems) boundary, and that's really little different from using the wrong calling convention. With binary interop you just have to make sure that everything is matching: argument types, return value types, function names, calling convention, the values passed to the function, etc.
What will happen if we dropped the stdcall in 64 bit?
There is a single calling convention for the Windows x64 platform. The calling convention directives are ignored by the compiler.
Although the 64 bit compiler ignores these directives it is still good practise to include them. That way your code will work when you compile it for 32 bit.
Is there any advantage in using Pointer instead Reference to classes?
for example:
TMyClass = class(TObject);
procedure Method;
var
pmc : ^TMyClass;
//instead of
mc : TMyClass;
begin
pmc := #ObjectMyClass;
//instead of
mc := ObjectMyClass;
if pmc.Enabled then
blablabla;
//instead of
if mc.Enabled then
blebleble;
end;
All classes in Delphi are passed/used by reference, so adding another level of indirection doesn't add anything.
This does not hold for records, which are always passed/used by value. One can use these by reference by declaring a pointer type and pass these to functions by using the pointer type or the var keyword (which handles the pointer function argument mess for you).
(Ctrl+F for "class")
http://docwiki.embarcadero.com/RADStudio/XE3/en/Pointers_and_Pointer_Types
In case you're familiar with C/C++, ^TMyClass is equivalent to:
**MyClass
This is useful in some cases like when you want to edit a pointer using a function by passing a pointer to the pointer to that function, but I doubt these constructions are possible using Delphi.
I am using Delphi 2010. Is it possible to tell Delphi to not generate a prologue for a function? I'm writing some pure assembly functions like this:
procedure SomeAssembly; stdcall;
begin
asm
...
end;
end;
and I would like to tell Delphi not to generate a prologue and epilogue for this function, like C++'s __declspec(naked) feature.
And so no one wastes their time, I don't need help getting these functions to work with the prologue; I can already do that. It's just a large inconvenience and will make maintenance an huge hassle. I'll have to manually inspect the prologues generated by the compiler to see their length, and if that changes, my program will crash.
I also know I can write the function as a series of bytes in a byte array, but that would be even worse than having to go find the length of Delphi's prologue.
Delphi doesn't generate prologues or epilogues for functions having no arguments and declared with the register calling convention. If you want functions without prologues, declare them as zero-argument, register-calling-convention functions. Also, skip the begin-end block and go straight into assembly.
procedure SomeAssembly; // register; (implied)
asm
// ...
end;
Since you're effectively lying about the nature of the functions, calling them may be tricky. If you've implemented a function as though it received parameters and used a different calling convention, then you'll have to make sure the compiler knows about that at the call site. To do that, declare a function pointer that reflects the "real" type of your function instead of the declared type. For example, if your function is really a two-argument stdcall function, declare something like this:
type
TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall;
var
SomeAssemblyProc: TSomeAssemblyProc;
Now, assign that variable so it points at your function:
SomeAssemblyProc := TSomeAssemblyProc(#SomeAssembly);
if SomeAssembly(2, 'foo') then ...
In addition to skipping the prologue and epilogue, the compiler will generate the incorrect RET instruction for this function (because of the different calling convention), so you'll have to make sure you say ret 8 in your code instead of letting the compiler's default ret instruction occur.
Finding the length of Delphi's prologue is trivial, if you have a working debugger:
Set a breakpoint at the start of the function.
Call the function.
When the debugger stops at the breakpoint, switch to the CPU view.
Look at the instructions that make up the prologue.
Count the bytes displayed beside those instructions.
According to the this embarcadero docwiki you can skip the surrounding begin and end and the compiler will skip some of it's stuff. But if you really want pure assembler, why not put your function into a separate assembler file, assemble it with tasm (the exe is named tasm32) and link to it. You'll then use the assembler directive in the delphi code.
Doesn't
procedure SomeAssembly; stdcall;
asm
...
end;
do the trick?