大家都来看一看,一个关于COM的简单问题

时间:2022-09-19 14:17:17
调用CoCreateInstance后得到了一个DLL(COM)的接口地址.
那然后比如我想调用里面的"speak".
怎么算接口表里函数的偏移? 
下面是用eXeScope打开这个DLL的部分内容
Interface ISpVoice; // ISpVoice Interface
GUID={6C44DF74-72B9-4992-A1EC-EF996E0422D4};
  function SetOutput(pUnkOutput:IUnknown; fAllowFormatChanges:I4): HResult;
  function GetOutputObjectToken(out ppObjectToken:^^ISpObjectToken): HResult;
  function GetOutputStream(out ppStream:^^ISpStreamFormat): HResult;
  function Pause: HResult;
  function Resume: HResult;
  function SetVoice(pToken:^ISpObjectToken): HResult;
  function GetVoice(out ppToken:^^ISpObjectToken): HResult;
  function Speak(pwcs:LPWSTR; dwFlags:UI4; out pulStreamNumber:^UI4): HResult;
  function SpeakStream(pStream:^IStream; dwFlags:UI4; out pulStreamNumber:^UI4): HResult;
  function GetStatus(out pStatus:^SPVOICESTATUS; out ppszLastBookmark:^LPWSTR): HResult;
  function Skip(pItemType:LPWSTR; lNumItems:I4; out pulNumSkipped:^UI4): HResult;
  function SetPriority(ePriority:SPVPRIORITY): HResult;
  function GetPriority(out pePriority:^SPVPRIORITY): HResult;
  function SetAlertBoundary(eBoundary:SPEVENTENUM): HResult;
  function GetAlertBoundary(out peBoundary:^SPEVENTENUM): HResult;
  function SetRate(RateAdjust:I4): HResult;
  function GetRate(out pRateAdjust:^I4): HResult;
  function SetVolume(usVolume:UI2): HResult;
  function GetVolume(out pusVolume:^UI2): HResult;
  function WaitUntilDone(msTimeout:UI4): HResult;
  function SetSyncSpeakTimeout(msTimeout:UI4): HResult;
  function GetSyncSpeakTimeout(out pmsTimeout:^UI4): HResult;
  function SpeakCompleteEvent: ^void;
  function IsUISupported(pszTypeOfUI:^UI2; pvExtraData:^void; cbExtraData:UI4; out pfSupported:^I4): HResult;
  function DisplayUI(hWndParent:wireHWND; pszTitle:^UI2; pszTypeOfUI:^UI2; pvExtraData:^void; cbExtraData:UI4): HResult; 

12 个解决方案

#1


接口都获得了,直接->Speak就可以了

#2


那用汇编呢,假如EAX是接口的地址,先把Speak的参数PUSH进栈,再CALL DWORD (EAX + 偏移),好像这个偏移是50H,但我自己算不对,哪位大侠来简单再说一说呀,怎么算的!

#3


不懂也

#4


牛啊

#5


怎么没人来帮助我这个菜鸟??

#6


引用 2 楼 linghu9990 的回复:
那用汇编呢,假如EAX是接口的地址,先把Speak的参数PUSH进栈,再CALL DWORD (EAX + 偏移),好像这个偏移是50H,但我自己算不对,哪位大侠来简单再说一说呀,怎么算的!

接口指向的地址才是函数地址开始的地方,也就是[EAX]+偏移 才是函数

#7


这是在网上看的别人的例子,编译成功,但不知那个偏移50咋来的!我本愚钝!
.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include kernel32.inc
   include ole32.inc
   
   includelib kernel32.lib
   includelib ole32.lib

.data
CLSID_SpVoice GUID <096749377h, 03391h, 011D2h, <09Eh, 0E3h, 000h, 0C0h, 04Fh, 079h, 073h, 096h>>
IID_ISpVoice  GUID <06C44DF74h, 072B9h, 04992h, <0A1h, 0ECh, 0EFh, 099h, 06Eh, 004h, 022h, 0D4h>>

TEXT    db 'I',0,' ',0 ,'L',0 ,'o',0 ,'v',0 ,'e',0 ,' ',0 ,'Y',0 ,'o',0 ,'u',0 ,'!',0,0

.data?
PCOM    dd ?
.code

; ---------------------------------------------------------------------------

start:
    invoke CoInitialize,0
    invoke CoCreateInstance,offset CLSID_SpVoice, 0, CLSCTX_INPROC_SERVER, offset IID_ISpVoice,offset PCOM
    .if eax == 0
        push 0
        push 0
        push offset TEXT
        mov eax,PCOM
        push eax
        mov eax,[eax]
        call DWORD PTR[eax+50h] ;PCOM->Speak(L"I LOVE YOU!", 0, 0);
    .endif
    invoke ExitProcess,eax

end start

#8


我也不知道50是怎么来的,也问问别人。
按理说,Speak函数是第7个函数,那么实际函数就是第10个函数(接口最开始的还有3个默认函数)
也就是说,偏移量应该是10*4=40=28h才是,但是现在是50h=80,难道每个函数使用的是8个字节?

#9


估计是还和参数有关呀

#10


和参数没啥关系,是因为此接口不是直接从IUnknown继承的,
ISpvoice <-- ISpEventSource <-- ISpNotifySource <-- IUnknown
你数数里头的接口数目,正好是第21个接口,也就是相对偏移50h

#11


正如doudouHuY大哥所教!
谢谢大家帮忙,感激不尽!

#12


你去看看COM原理与应用,里面有说的。就是指针首先是指向VTL,每个虚函数的指针占一定空间,顺着下去就可以了。好像是这样,我当时也没看的太认真。

#1


接口都获得了,直接->Speak就可以了

#2


那用汇编呢,假如EAX是接口的地址,先把Speak的参数PUSH进栈,再CALL DWORD (EAX + 偏移),好像这个偏移是50H,但我自己算不对,哪位大侠来简单再说一说呀,怎么算的!

#3


不懂也

#4


牛啊

#5


怎么没人来帮助我这个菜鸟??

#6


引用 2 楼 linghu9990 的回复:
那用汇编呢,假如EAX是接口的地址,先把Speak的参数PUSH进栈,再CALL DWORD (EAX + 偏移),好像这个偏移是50H,但我自己算不对,哪位大侠来简单再说一说呀,怎么算的!

接口指向的地址才是函数地址开始的地方,也就是[EAX]+偏移 才是函数

#7


这是在网上看的别人的例子,编译成功,但不知那个偏移50咋来的!我本愚钝!
.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include kernel32.inc
   include ole32.inc
   
   includelib kernel32.lib
   includelib ole32.lib

.data
CLSID_SpVoice GUID <096749377h, 03391h, 011D2h, <09Eh, 0E3h, 000h, 0C0h, 04Fh, 079h, 073h, 096h>>
IID_ISpVoice  GUID <06C44DF74h, 072B9h, 04992h, <0A1h, 0ECh, 0EFh, 099h, 06Eh, 004h, 022h, 0D4h>>

TEXT    db 'I',0,' ',0 ,'L',0 ,'o',0 ,'v',0 ,'e',0 ,' ',0 ,'Y',0 ,'o',0 ,'u',0 ,'!',0,0

.data?
PCOM    dd ?
.code

; ---------------------------------------------------------------------------

start:
    invoke CoInitialize,0
    invoke CoCreateInstance,offset CLSID_SpVoice, 0, CLSCTX_INPROC_SERVER, offset IID_ISpVoice,offset PCOM
    .if eax == 0
        push 0
        push 0
        push offset TEXT
        mov eax,PCOM
        push eax
        mov eax,[eax]
        call DWORD PTR[eax+50h] ;PCOM->Speak(L"I LOVE YOU!", 0, 0);
    .endif
    invoke ExitProcess,eax

end start

#8


我也不知道50是怎么来的,也问问别人。
按理说,Speak函数是第7个函数,那么实际函数就是第10个函数(接口最开始的还有3个默认函数)
也就是说,偏移量应该是10*4=40=28h才是,但是现在是50h=80,难道每个函数使用的是8个字节?

#9


估计是还和参数有关呀

#10


和参数没啥关系,是因为此接口不是直接从IUnknown继承的,
ISpvoice <-- ISpEventSource <-- ISpNotifySource <-- IUnknown
你数数里头的接口数目,正好是第21个接口,也就是相对偏移50h

#11


正如doudouHuY大哥所教!
谢谢大家帮忙,感激不尽!

#12


你去看看COM原理与应用,里面有说的。就是指针首先是指向VTL,每个虚函数的指针占一定空间,顺着下去就可以了。好像是这样,我当时也没看的太认真。