CoInitialize淺析一


大家都知道程序中若要使用COM組件則必需要先調用CoInitialize,該函數主要是用來初始化COM執行環境。但這個函數的作用域是以線程為單位還是以進程為單位呢?或許大家已經通過測試程序摸索出答案,沒錯,是以線程為單位。今天我們就略微再深入一下,通過分析CoInitialize的詳細實現來印證我們的想法。

我們先來看看CoInitialize的匯編

769B2A24                 mov     edi, edi

769B2A26                 push    ebp

769B2A27                 mov     ebp, esp

769B2A29                 push    2               ; dwCoInit

769B2A2B                 push    [ebp+8] ; pvReserved

769B2A2E                 call   _CoInitializeEx@8 ; CoInitializeEx(x,x)

769B2A33                 pop     ebp

769B2A34                 retn    4

能夠看到,當中的實現還是比較簡單的,它僅僅是簡單地調用了CoInitializeEx,將第二個參數設置為2,即COINIT_APARTMENTTHREADED。我們再來看看CoInitializeEx的實現

769AEF5B                 mov     edi, edi

769AEF5D                 push    ebp

769AEF5E                 mov     ebp, esp

769AEF60                 push    ecx

769AEF61                 push    ebx

769AEF62                 mov     ebx, [ebp+0C]

769AEF65                 mov     eax, ebx

769AEF67                 and    eax, 0Eh      ; 檢查參數是否正確,眼下第二個參數僅僅用了一個字節

769AEF6A                 cmp     eax, ebx

769AEF6C                 jnz     loc_76A0B8C7

769AEF72                 push    edi

769AEF73                 xor     edi, edi

769AEF75                 cmp     [ebp+8], edi       ; 推斷第一個參數是否為NULL

769AEF78                 jnz     loc_76A0B8D1

769AEF7E

769AEF7Eloc_769AEF7E:

769AEF7E                 call    ?IsRunningInRPCSS@@YGHXZ ;IsRunningInRPCSS(void)

769AEF83                 test    eax, eax                                                          ;推斷當前進程是否是RPCSS

769AEF85                 jnz     loc_76A0B8ED                                             ;假設是(即返回非0)則返回“災難性故障”的錯誤

769AEF8B                 mov     eax, large fs:18h

769AEF91                 mov     eax, [eax+0F80h]

769AEF97                 cmp     eax, edi

769AEF99                 mov     [ebp+8], eax

769AEF9C                 jz      loc_769ADF26                                              ; 推斷當前線程中的struct tagSOleTlsData結構體是否分配,若未分配則進行分配

769AEFA2

769AEFA2loc_769AEFA2:

769AEFA2                 push    esi

769AEFA3                 push    edi             ; __int32

769AEFA4                 push    ebx             ; unsigned __int32

769AEFA5                 xor     esi, esi

769AEFA7                 inc     esi

769AEFA8                 push    esi             ; int

769AEFA9                 push    esi             ; int

769AEFAA                 call    ?NotifyInitializeSpies@@YGJHHKJ@Z ;NotifyInitializeSpies(int,int,ulong,long)

769AEFAF                 call    ?IsThreadInNTA@@YGHXZ ; IsThreadInNTA(void)

769AEFB4                 test    eax, eax

769AEFB6                 jnz     loc_769DAFAD                                            ; 假設是 則返回“無法在設置線程模式后對其加以更改。”的錯誤

769AEFBC                 mov     eax, [ebp+8]

769AEFBF                 mov     ecx, [eax+0Ch]

769AEFC2                 test    ch, 10h                                                          ;推斷標識第4位(從第0位開始)是否置位

769AEFC5                 jnz     loc_769D9D20                                              ; server出現意外情況。

769AEFCB                 mov     edx, ebx

769AEFCD                 and     edx, 2

769AEFD0                 mov     [ebp-4], edx                                 

769AEFD3                 jz      short loc_769AEFDE                      ; 非COINIT_APARTMENTTHREADED模式

769AEFD5                 test    ch, 1                                                                    ;推斷標識第0位是否置位

769AEFD8                 jnz     loc_769DAFAD                                            ; 返回“無法在設置線程模式后對其加以更改。”的錯誤

769AEFDE

769AEFDEloc_769AEFDE:

769AEFDE                 cmp     edx, edi                                                            

769AEFE0                 jz      loc_769DAFA5                                             ; 非COINIT_APARTMENTTHREADED模式

769AEFE6

769AEFE6loc_769AEFE6:

769AEFE6                 test    bl, 8

769AEFE9                 jnz     loc_76A0B901                                              ;第二個參數中COINIT_SPEED_OVER_MEMORY標識位被設置,即為單線程套件

769AEFEF

769AEFEFloc_769AEFEF:

769AEFEF                 add     eax, 18h

769AEFF2                 inc     dword ptr [eax]                               ; tagSOleTlsData.dwReserved1[0]++;

769AEFF4                 cmp     [eax], esi                                                    

769AEFF6                 jnz     loc_769ADBF9                                             ; 推斷tagSOleTlsData.dwReserved1[0]==1?

769AEFFC                 test    edx, edx

769AEFFE                 mov     ebx, offset?gMTAInitLock@@3VCOleStaticMutexSem@@A ; COleStaticMutexSem gMTAInitLock

769AF003                 jz      loc_769DAFF2                                              ; 第二個參數未設置COINIT_APARTMENTTHREADED標識,即為多線程套件

769AF009

769AF009loc_769AF009:

769AF009                 mov     esi, offset?g_mxsSingleThreadOle@@3VCOleStaticMutexSem@@A ; COleStaticMutexSemg_mxsSingleThreadOle

769AF00E                 mov     ecx, esi

769AF010                 call    ?Request@COleStaticMutexSem@@QAEXXZ ;COleStaticMutexSem::Request(void)

769AF015                 push    [ebp+0C]

769AF018                 lea     eax, [ebp+8]

769AF01B                 push    eax

769AF01C                 call    ?wCoInitializeEx@@YGJAAVCOleTls@@K@Z ;wCoInitializeEx(COleTls &,ulong)  調用wCoInitializeEx

769AF021                 mov     ecx, esi

769AF023                 mov     edi, eax

769AF025                 call    ?Release@COleStaticMutexSem@@QAEXXZ ;COleStaticMutexSem::Release(void)

769AF02A                 test    edi, edi

769AF02C                 jl      loc_76A0B90C

769AF032

769AF032loc_769AF032:

769AF032                 cmp     [ebp-4], 0         

769AF036                 jz      loc_769DB004                   ; 第二個參數未設置COINIT_APARTMENTTHREADED標識,即為多線程套件

769AF03C

769AF03C loc_769AF03C:                           ; CODE XREF:CoInitializeEx(x,x)+2C0B6j

769AF03C                xor     esi, esi

769AF03E                 inc     esi

769AF03F

769AF03F loc_769AF03F:

769AF03F                 push    edi             ; __int32

769AF040                 push    [ebp+0C]  ; unsigned__int32

769AF043                 push    0              ; int

769AF045                 push    esi             ; int

769AF046                 call    ?NotifyInitializeSpies@@YGJHHKJ@Z ;NotifyInitializeSpies(int,int,ulong,long)

769AF04B                 pop     esi

769AF04C

769AF04C loc_769AF04C:

769AF04C                 pop     edi

769AF04D

769AF04Dloc_769AF04D:

769AF04D                 pop     ebx

769AF04E                 leave

769AF04F                 retn    8

當中有幾點請注意:

1、在第一個參數為非空時,該函數會推斷當前進程是否為EXCEL;

2、該函數也會推斷當前進程是否為RPCSS,該進程的用途請大家另行查閱;檢查進程是否為RPCSS的方法主要是:先推斷當前進程是否有加載Windows文件夾下\\system32\\rpcss.dll,假設未加載則當前進程不是RPCSS;若加載了,則獲取該DLL中名為WhichService的導出函數,假設未找到該函數也覺得當前進程是RPCSS;若找到,並該函數的返回值大於等於0,且作為該函數參數的指針所指向的值為2則當前進程不是RPCSS,否則當前進程即為RPCSS。

3、每一個線程的TEB結構向后偏移0x0F80的地方存放struct tagSOleTlsData的指針,該結構的聲明例如以下:

typedef structtagSOleTlsData

{

    void *pvReserved0[2];

    DWORD dwReserved0[3];

    void *pvReserved1[1];

    DWORD dwReserved1[3];

    void *pvReserved2[4];

    DWORD dwReserved2[1];

    void *pCurrentCtx;

} SOleTlsData;

該結構中存放了當前線程有關COM的環境信息,這個結構體中各個域的定義微軟貌似沒有公開。線程啟動后,在沒有該線程調用CoInitialize或CoInitializeEx之前,該指針為空。第一次調用上述函數后,為該線程從堆上分配該結構的內存並將其指針保存至TEB+0x0F80處。

4、我們注意到,全部對struct tagSOleTlsData內容的改動都未進行相互排斥保護,這是由於全部對該結構的改動操作都在當前線程內部進行,因此也就不存在多線程同步的問題;而對於一些全局信息的改動則都進行了保護。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM