Everyone knows that to use COM components in a program, you must first call coinitialize. This function is mainly used to initialize the com runtime environment. But does the function scope take the thread as the unit or the process as the unit? Maybe you have figured out the answer through the test program. That's right, it's a thread. Today, we will go into a bit more detail and confirm our ideas by analyzing the specific implementation of coinitialize.
Let's take a look at coinitialize compilation.
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
We can see that the implementation is still relatively simple. It just calls coinitializeex and sets the second parameter to 2, that is, coinit_apartmentthreaded. Let's take a look at the implementation of 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; check whether the parameter is correct. Currently, the second parameter only uses one byte.
769aef6a CMP eax, EBX
769aef6c jnz loc_76a0b8c7
769aef72 push EDI
769aef73 xor edi, EDI
769aef75 CMP [EBP + 8], EDI; Determine whether the first parameter is null
769aef78 jnz loc_76a0b8d1
769aef7e
769aef7eloc_769aef7e:
769aef7e call? Isrunninginrpcss @ yghxz; isrunninginrpcss (void)
769aef83 test eax, eax; judge whether the current process is RPCSS
769aef85 jnz loc_76a0b8ed; If yes (that is, non-0 is returned), a "catastrophic fault" error is returned.
769aef8b mov eax, large FS: 18 h
769aef91 mov eax, [eax + 0f80h]
769aef97 CMP eax, EDI
769aef99 mov [EBP + 8], eax
769aef9c JZ loc_769adf26; determines whether the struct tagsoletlsdata struct in the current thread is allocated. If not, allocate the struct.
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
769 aefaa call? Notifyinitializespies @ ygjhhkj @ Z; notifyinitializespies (INT, Int, ulong, long)
769 aefaf call? Isthreadinnta @ yghxz; isthreadinnta (void)
769aefb4 test eax, eax
769aefb6 jnz loc_769dafad; If yes, "cannot be changed after thread mode is set" is returned ." Error
769 aefbc mov eax, [EBP + 8]
769 aefbf mov ECx, [eax + 0ch]
769aefc2 test CH, 10 h; Determine whether to set the 4th bits (starting from 0th bits)
769aefc5 jnz loc_769d9d20; server exceptions.
769 aefcb mov edX, EBX
769 aefcd and EDX, 2
769aefd0 mov [ebp-4], EDX
769aefd3 JZ short loc_769aefde; non-coinit_apartmentthreaded Mode
769aefd5 test CH, 1; identify whether 0th bits are set
769aefd8 jnz loc_769dafad; "cannot be changed after thread mode is set" is returned ." Error
769 aefde
769aefdeloc_769aefde:
769 aefde CMP edX, EDI
769aefe0 JZ loc_769dafa5; non-coinit_apartmentthreaded Mode
769aefe6
769aefe6loc_769aefe6:
769aefe6 test BL, 8
769aefe9 jnz loc_76a0b901; in the second parameter, the coinit_speed_over_memory identifier is set, that is, the single-thread kit.
769 aefef
769aefefloc_769aefef:
769 aefef add eax, 18 h
769aeff2 Inc dword ptr [eax]; tagsoletlsdata. dwreserved1 [0] ++;
769aeff4 CMP [eax], ESI
769aeff6 jnz loc_769adbf9; Judge tagsoletlsdata. dwreserved1 [0] = 1?
769 aeffc test edX, EDX
769 aeffe mov EBX, offset? Gmtainitlock @ 3vcolestaticmutexsem @ A; colestaticmutexsem gmtainitlock
769af003 JZ loc_769daff2; the second parameter is not set with the coinit_apartmentthreaded identifier, that is, the multi-thread suite
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) calls 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; the second parameter is not set with the coinit_apartmentthreaded identifier, that is, the multi-thread suite
769af03c
769af03c loc_769af03c:; Code xref: coinitializeex (x, x) + 2c0b4.7
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
Note the following points:
1. When the first parameter is not blank, the function determines whether the current process is Excel;
2. This function will also determine whether the current process is RPCSS. For details about the purpose of this process, refer to the following methods to check whether the process is RPCSS: first, determine whether the current process has been loaded into the Windows directory \ system32 \ RPCSS. DLL. If it is not loaded, the current process is not RPCSS. If it is loaded, obtain the export function named whichservice In the DLL. If the function is not found, the current process is considered as RPCSS; if it is found, and the return value of this function is greater than or equal to 0, and the pointer to this function parameter points to 2, the current process is not RPCSS; otherwise, the current process is RPCSS.
3. The Teb structure of each thread is offset to 0x0f80 to store the pointer of struct tagsoletlsdata. The declaration of this structure is as follows:
Typedef structtagsoletlsdata
{
Void * pvreserved0 [2];
DWORD dwreserved0 [3];
Void * pvreserved1 [1];
DWORD dwreserved1 [3];
Void * pvreserved2 [4];
DWORD dwreserved2 [1];
Void * pcurrentctx;
} Soletlsdata;
This structure stores information about the com environment of the current thread. The definition of each domain in this struct does not seem to be made public by Microsoft. After the thread starts, the pointer is blank before the thread calls coinitialize or coinitializeex. After the above function is called for the first time, allocate the memory of the structure to the thread from the heap and save the pointer to Teb + 0x0f80.
4. We noticed that all modifications to the struct tagsoletlsdata content are not mutually exclusive, because all modifications to this structure are performed within the current thread, therefore, multi-thread synchronization does not occur. Modifications to some global information are protected.