Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

959 lines
25 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. ShimHook.cpp
  5. Abstract:
  6. Strictly Shim hooking routines.
  7. Notes:
  8. None
  9. History:
  10. 11/01/1999 markder Created
  11. 11/11/1999 markder Added comments
  12. 01/10/2000 linstev Format to new style
  13. 03/14/2000 robkenny Changed DPF from eDebugLevelInfo to eDebugLevelSpew
  14. 03/31/2000 robkenny Added our own private versions of malloc/free new/delete
  15. 10/29/2000 markder Added version 2 support
  16. 08/14/2001 robkenny Moved generic routines to ShimLib.cpp
  17. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  18. --*/
  19. #include "ShimHook.h"
  20. #include "ShimHookMacro.h"
  21. #include "StrSafe.h"
  22. namespace ShimLib
  23. {
  24. HINSTANCE g_hinstDll;
  25. BOOL g_bMultiShim;
  26. PHOOKAPI g_pAPIHooks;
  27. PSHIM_COM_HOOK g_pCOMHooks;
  28. DWORD g_dwAPIHookCount;
  29. DWORD g_dwCOMHookCount;
  30. DWORD g_dwCOMHookBuffer;
  31. DWORD g_dwShimVersion;
  32. CHAR * g_szCommandLine;
  33. /*++
  34. Global variables for COM hook support
  35. The following variables are pointers to the first entry in linked lists that
  36. are maintained by the mechanism in order to properly manage the hooking
  37. process.
  38. There will be one SHIM_IFACE_FN_MAP for every COM interface function pointer
  39. that was overwritten with one of our hooks.
  40. There will be one SHIM_HOOKED_OBJECT entry every COM interface that is handed
  41. out. This is required to differentiate between different classes that expose
  42. the same interface, but one is hooked and one isn't.
  43. --*/
  44. PSHIM_IFACE_FN_MAP g_pIFaceFnMaps;
  45. PSHIM_HOOKED_OBJECT g_pObjectCache;
  46. PLDR_DATA_TABLE_ENTRY g_DllLoadingEntry;
  47. PHOOKAPI GetHookAPIs( IN LPSTR pszCmdLine, IN LPWSTR pwszShim, IN OUT DWORD *pdwHooksCount );
  48. void PatchFunction( PVOID* pVtbl, DWORD dwVtblIndex, PVOID pfnNew );
  49. ULONG COMHook_AddRef( PVOID pThis );
  50. ULONG COMHook_Release( PVOID pThis );
  51. HRESULT COMHook_QueryInterface( PVOID pThis, REFIID iid, PVOID* ppvObject );
  52. HRESULT COMHook_IClassFactory_CreateInstance( PVOID pThis, IUnknown * pUnkOuter, REFIID riid, void ** ppvObject );
  53. VOID HookObject(IN CLSID *pCLSID, IN REFIID riid, OUT LPVOID *ppv, OUT PSHIM_HOOKED_OBJECT pOb, IN BOOL bClassFactory);
  54. void
  55. NotifyShims(
  56. int nReason,
  57. UINT_PTR extraInfo
  58. )
  59. {
  60. switch (nReason) {
  61. case SN_STATIC_DLLS_INITIALIZED:
  62. InitializeHooksEx(SHIM_STATIC_DLLS_INITIALIZED, NULL, NULL, NULL);
  63. break;
  64. case SN_PROCESS_DYING:
  65. InitializeHooksEx(SHIM_PROCESS_DYING, NULL, NULL, NULL);
  66. break;
  67. case SN_DLL_LOADING:
  68. g_DllLoadingEntry = (PLDR_DATA_TABLE_ENTRY)extraInfo;
  69. InitializeHooksEx(SHIM_DLL_LOADING, NULL, NULL, NULL);
  70. break;
  71. }
  72. }
  73. /*++
  74. Function Description:
  75. Called by the shim mechanism. Initializes the global APIHook array and
  76. returns necessary information to the shim mechanism.
  77. Arguments:
  78. IN dwGetProcAddress - Function pointer to GetProcAddress
  79. IN dwLoadLibraryA - Function pointer to LoadLibraryA
  80. IN dwFreeLibrary - Function pointer to FreeLibrary
  81. IN OUT pdwHooksCount - Receive the number of APIHooks in the returned array
  82. Return Value:
  83. Pointer to global HOOKAPI array.
  84. History:
  85. 11/01/1999 markder Created
  86. --*/
  87. PHOOKAPI
  88. GetHookAPIs(
  89. IN LPSTR pszCmdLine,
  90. IN LPWSTR pwszShim,
  91. IN OUT DWORD * pdwHooksCount
  92. )
  93. {
  94. PHOOKAPI pHookAPIs = NULL;
  95. pHookAPIs = InitializeHooksEx(DLL_PROCESS_ATTACH, pwszShim, pszCmdLine, pdwHooksCount);
  96. DPF("ShimLib", eDbgLevelBase,
  97. "[Shim] %S%s%s%s\n",
  98. pwszShim,
  99. pszCmdLine[0] != '\0' ? "(\"" : "",
  100. pszCmdLine,
  101. pszCmdLine[0] != '\0' ? "\")" : "");
  102. return pHookAPIs;
  103. }
  104. /*++
  105. Function Description:
  106. Adds an entry to the g_IFaceFnMaps linked list.
  107. Arguments:
  108. IN pVtbl - Pointer to an interface vtable to file under
  109. IN pfnNew - Pointer to the new (stub) function
  110. IN pfnOld - Pointer to the old (original) function
  111. Return Value:
  112. None
  113. History:
  114. 11/01/1999 markder Created
  115. --*/
  116. VOID
  117. AddIFaceFnMap(
  118. IN PVOID pVtbl,
  119. IN PVOID pfnNew,
  120. IN PVOID pfnOld
  121. )
  122. {
  123. PSHIM_IFACE_FN_MAP pNewMap = (PSHIM_IFACE_FN_MAP) ShimMalloc( sizeof(SHIM_IFACE_FN_MAP) );
  124. if (pNewMap == NULL)
  125. {
  126. DPF("ShimLib", eDbgLevelError, "[AddIFaceFnMap] Could not allocate space for new SHIM_IFACE_FN_MAP.\n");
  127. return;
  128. }
  129. DPF("ShimLib", eDbgLevelSpew, "[AddIFaceFnMap] pVtbl: 0x%p pfnNew: 0x%p pfnOld: 0x%p\n",
  130. pVtbl,
  131. pfnNew,
  132. pfnOld);
  133. pNewMap->pVtbl = pVtbl;
  134. pNewMap->pfnNew = pfnNew;
  135. pNewMap->pfnOld = pfnOld;
  136. pNewMap->pNext = g_pIFaceFnMaps;
  137. g_pIFaceFnMaps = pNewMap;
  138. }
  139. /*++
  140. Function Description:
  141. Searches the g_pIFaceFnMaps linked list for a match on pVtbl and pfnNew, and
  142. returns the corresponding pfnOld. This is typically called from inside a
  143. stubbed function to determine what original function pointer to call for the
  144. particular vtable that was used by the caller.
  145. It is also used by PatchFunction to determine if a vtable's function pointer
  146. has already been stubbed.
  147. Arguments:
  148. IN pVtbl - Pointer to an interface vtable to file under
  149. IN pfnNew - Pointer to the new (stub) function
  150. IN bThrowExceptionIfNull - Flag that specifies whether it should be
  151. possible to not find the original function in our function
  152. map
  153. Return Value:
  154. Returns the original function pointer
  155. History:
  156. 11/01/1999 markder Created
  157. --*/
  158. PVOID
  159. LookupOriginalCOMFunction(
  160. IN PVOID pVtbl,
  161. IN PVOID pfnNew,
  162. IN BOOL bThrowExceptionIfNull
  163. )
  164. {
  165. PSHIM_IFACE_FN_MAP pMap = g_pIFaceFnMaps;
  166. PVOID pReturn = NULL;
  167. DPF("ShimLib", eDbgLevelSpew, "[LookupOriginalCOMFunction] pVtbl: 0x%p pfnNew: 0x%p ",
  168. pVtbl,
  169. pfnNew);
  170. // Scan the linked list for a match and return if found.
  171. while (pMap)
  172. {
  173. if (pMap->pVtbl == pVtbl && pMap->pfnNew == pfnNew)
  174. {
  175. pReturn = pMap->pfnOld;
  176. break;
  177. }
  178. pMap = (PSHIM_IFACE_FN_MAP) pMap->pNext;
  179. }
  180. DPF("ShimLib", eDbgLevelSpew, " --> Returned: 0x%p\n", pReturn);
  181. if (!pReturn && bThrowExceptionIfNull)
  182. {
  183. // If we have hit this point, there is something seriously wrong.
  184. // Either there is a bug in the AddRef/Release stubs or the app
  185. // obtained an interface pointer in some way that we don't catch.
  186. DPF("ShimLib", eDbgLevelError,"ERROR: Shim COM APIHooking mechanism failed.\n");
  187. APPBreakPoint();
  188. }
  189. return pReturn;
  190. }
  191. /*++
  192. Function Description:
  193. Stores the original function pointer in the function map and overwrites it in
  194. the vtable with the new one.
  195. Arguments:
  196. IN pVtbl - Pointer to an interface vtable to file under
  197. IN dwVtblIndex - The index of the target function within the vtable.
  198. IN pfnNew - Pointer to the new (stub) function
  199. Return Value:
  200. None
  201. History:
  202. 11/01/1999 markder Created
  203. --*/
  204. VOID
  205. PatchFunction(
  206. IN PVOID* pVtbl,
  207. IN DWORD dwVtblIndex,
  208. IN PVOID pfnNew
  209. )
  210. {
  211. DWORD dwOldProtect = 0;
  212. DWORD dwOldProtect2 = 0;
  213. DPF("ShimLib", eDbgLevelSpew, "[PatchFunction] pVtbl: 0x%p, dwVtblIndex: %d, pfnOld: 0x%p, pfnNew: 0x%p\n",
  214. pVtbl,
  215. dwVtblIndex,
  216. pVtbl[dwVtblIndex],
  217. pfnNew);
  218. // if not patched yet
  219. if (!LookupOriginalCOMFunction( pVtbl, pfnNew, FALSE))
  220. {
  221. AddIFaceFnMap( pVtbl, pfnNew, pVtbl[dwVtblIndex]);
  222. // Make the code page writable and overwrite function pointers in vtable
  223. if (VirtualProtect(pVtbl + dwVtblIndex,
  224. sizeof(DWORD),
  225. PAGE_READWRITE,
  226. &dwOldProtect))
  227. {
  228. pVtbl[dwVtblIndex] = pfnNew;
  229. // Return the code page to its original state
  230. VirtualProtect(pVtbl + dwVtblIndex,
  231. sizeof(DWORD),
  232. dwOldProtect,
  233. &dwOldProtect2);
  234. }
  235. }
  236. }
  237. /*++
  238. Function Description:
  239. This stub exists to keep track of an interface's reference count changes.
  240. Note that the bAddRefTrip flag is cleared, which allows
  241. APIHook_QueryInterface to determine whether an AddRef was performed inside
  242. the original QueryInterface function call.
  243. Arguments:
  244. IN pThis - The object's 'this' pointer
  245. Return Value:
  246. Return value is obtained from original function
  247. History:
  248. 11/01/1999 markder Created
  249. --*/
  250. ULONG
  251. APIHook_AddRef(
  252. IN PVOID pThis
  253. )
  254. {
  255. PSHIM_HOOKED_OBJECT pHookedOb = g_pObjectCache;
  256. _pfn_AddRef pfnOld;
  257. ULONG ulReturn;
  258. pfnOld = (_pfn_AddRef) LookupOriginalCOMFunction( *((PVOID*)(pThis)),
  259. APIHook_AddRef,
  260. TRUE);
  261. ulReturn = (*pfnOld)(pThis);
  262. while (pHookedOb)
  263. {
  264. if (pHookedOb->pThis == pThis)
  265. {
  266. pHookedOb->dwRef++;
  267. pHookedOb->bAddRefTrip = FALSE;
  268. DPF("ShimLib", eDbgLevelSpew, "[AddRef] pThis: 0x%p dwRef: %d ulReturn: %d\n",
  269. pThis,
  270. pHookedOb->dwRef,
  271. ulReturn);
  272. break;
  273. }
  274. pHookedOb = (PSHIM_HOOKED_OBJECT) pHookedOb->pNext;
  275. }
  276. return ulReturn;
  277. }
  278. /*++
  279. Function Description:
  280. This stub exists to keep track of an interface's reference count changes.
  281. Arguments:
  282. IN pThis - The object's 'this' pointer
  283. Return Value:
  284. Return value is obtained from original function
  285. History:
  286. 11/01/1999 markder Created
  287. --*/
  288. ULONG
  289. APIHook_Release(
  290. IN PVOID pThis
  291. )
  292. {
  293. PSHIM_HOOKED_OBJECT *ppHookedOb = &g_pObjectCache;
  294. PSHIM_HOOKED_OBJECT pTemp;
  295. _pfn_Release pfnOld;
  296. ULONG ulReturn;
  297. pfnOld = (_pfn_Release) LookupOriginalCOMFunction(*((PVOID*)(pThis)),
  298. APIHook_Release,
  299. TRUE);
  300. ulReturn = (*pfnOld)( pThis );
  301. while ((*ppHookedOb))
  302. {
  303. if ((*ppHookedOb)->pThis == pThis)
  304. {
  305. (*ppHookedOb)->dwRef--;
  306. DPF("ShimLib", eDbgLevelSpew, "[Release] pThis: 0x%p dwRef: %d ulReturn: %d %s\n",
  307. pThis,
  308. (*ppHookedOb)->dwRef,
  309. ulReturn,
  310. ((*ppHookedOb)->dwRef?"":" --> Deleted"));
  311. if (!((*ppHookedOb)->dwRef))
  312. {
  313. pTemp = (*ppHookedOb);
  314. *ppHookedOb = (PSHIM_HOOKED_OBJECT) (*ppHookedOb)->pNext;
  315. ShimFree(pTemp);
  316. }
  317. break;
  318. }
  319. ppHookedOb = (PSHIM_HOOKED_OBJECT*) &((*ppHookedOb)->pNext);
  320. }
  321. return ulReturn;
  322. }
  323. /*++
  324. Function Description:
  325. This stub catches the application attempting to obtain a new interface
  326. pointer to the same object. The function searches the object cache
  327. to obtain a CLSID for the object and, if found, APIHooks all required
  328. functions in the new vtable (via the HookObject call).
  329. Arguments:
  330. IN pThis - The object's 'this' pointer
  331. IN iid - Reference to the identifier of the requested interface
  332. IN ppvObject - Address of output variable that receives the interface
  333. pointer requested in riid.
  334. Return Value:
  335. Return value is obtained from original function
  336. History:
  337. 11/01/1999 markder Created
  338. --*/
  339. HRESULT
  340. APIHook_QueryInterface(
  341. PVOID pThis,
  342. REFIID iid,
  343. PVOID* ppvObject
  344. )
  345. {
  346. HRESULT hrReturn = E_FAIL;
  347. _pfn_QueryInterface pfnOld = NULL;
  348. PSHIM_HOOKED_OBJECT pOb = g_pObjectCache;
  349. pfnOld = (_pfn_QueryInterface) LookupOriginalCOMFunction(
  350. *((PVOID*)pThis),
  351. APIHook_QueryInterface,
  352. TRUE);
  353. while (pOb)
  354. {
  355. if (pOb->pThis == pThis)
  356. {
  357. pOb->bAddRefTrip = TRUE;
  358. break;
  359. }
  360. pOb = (PSHIM_HOOKED_OBJECT) pOb->pNext;
  361. }
  362. if (S_OK == (hrReturn = (*pfnOld) (pThis, iid, ppvObject)))
  363. {
  364. if (pOb)
  365. {
  366. if (pOb->pThis == *((PVOID*)ppvObject))
  367. {
  368. // Same object. Detect whether QueryInterface used IUnknown::AddRef
  369. // or an internal function.
  370. DPF("ShimLib", eDbgLevelSpew,"[HookObject] Existing object%s. pThis: 0x%p\n",
  371. (pOb->bAddRefTrip?" (AddRef'd) ":""),
  372. pOb->pThis);
  373. if (pOb->bAddRefTrip)
  374. {
  375. (pOb->dwRef)++; // AddRef the object
  376. pOb->bAddRefTrip = FALSE;
  377. }
  378. // We are assured that the CLSID for the object will be the same.
  379. HookObject(pOb->pCLSID, iid, ppvObject, pOb, pOb->bClassFactory);
  380. }
  381. else
  382. {
  383. HookObject(pOb->pCLSID, iid, ppvObject, NULL, pOb->bClassFactory);
  384. }
  385. }
  386. }
  387. return hrReturn;
  388. }
  389. /*++
  390. Function Description:
  391. This stub catches the most interesting part of the object creation process:
  392. The actual call to IClassFactory::CreateInstance. Since no CLSID is passed
  393. in to this function, the stub must decide whether to APIHook the object by
  394. looking up the instance of the class factory in the object cache. IF IT
  395. EXISTS IN THE CACHE, that indicates that it creates an object that we wish
  396. to APIHook.
  397. Arguments:
  398. IN pThis - The object's 'this' pointer
  399. IN pUnkOuter - Pointer to whether object is or isn't part of an aggregate
  400. IN riid - Reference to the identifier of the interface
  401. OUT ppvObject - Address of output variable that receives the interface
  402. pointer requested in riid
  403. Return Value:
  404. Return value is obtained from original function
  405. History:
  406. 11/01/1999 markder Created
  407. --*/
  408. HRESULT
  409. APIHook_IClassFactory_CreateInstance(
  410. PVOID pThis,
  411. IUnknown *pUnkOuter,
  412. REFIID riid,
  413. VOID **ppvObject
  414. )
  415. {
  416. HRESULT hrReturn = E_FAIL;
  417. _pfn_CreateInstance pfnOldCreateInst = NULL;
  418. PSHIM_HOOKED_OBJECT pOb = g_pObjectCache;
  419. pfnOldCreateInst = (_pfn_CreateInstance) LookupOriginalCOMFunction(
  420. *((PVOID*)pThis),
  421. APIHook_IClassFactory_CreateInstance,
  422. FALSE);
  423. if (pfnOldCreateInst == NULL) {
  424. DPF("ShimLib", eDbgLevelError, "[CreateInstance] Cannot find CreateInstance\n", pThis);
  425. return E_FAIL;
  426. }
  427. if (S_OK == (hrReturn = (*pfnOldCreateInst)(pThis, pUnkOuter, riid, ppvObject)))
  428. {
  429. while (pOb)
  430. {
  431. if (pOb->pThis == pThis)
  432. {
  433. // This class factory instance creates an object that we APIHook.
  434. DPF("ShimLib", eDbgLevelSpew, "[CreateInstance] Hooking object! pThis: 0x%p\n", pThis);
  435. HookObject(pOb->pCLSID, riid, ppvObject, NULL, FALSE);
  436. break;
  437. }
  438. pOb = (PSHIM_HOOKED_OBJECT) pOb->pNext;
  439. }
  440. }
  441. return hrReturn;
  442. }
  443. VOID
  444. HookCOMInterface(
  445. REFCLSID rclsid,
  446. REFIID riid,
  447. LPVOID * ppv,
  448. BOOL bClassFactory
  449. )
  450. {
  451. DWORD i = 0;
  452. // Determine if we need to hook this object
  453. for (i = 0; i < g_dwCOMHookCount; i++)
  454. {
  455. if (g_pCOMHooks[i].pCLSID &&
  456. IsEqualGUID( (REFCLSID) *(g_pCOMHooks[i].pCLSID), rclsid))
  457. {
  458. // Yes, we are hooking an interface on this object.
  459. HookObject((CLSID*) &rclsid, riid, ppv, NULL, bClassFactory);
  460. break;
  461. }
  462. }
  463. }
  464. /*++
  465. Function Description:
  466. Free memory associated with Hooks and dump info
  467. Arguments:
  468. None
  469. Return Value:
  470. None
  471. History:
  472. 11/01/1999 markder Created
  473. --*/
  474. VOID
  475. DumpCOMHooks()
  476. {
  477. PSHIM_IFACE_FN_MAP pMap = g_pIFaceFnMaps;
  478. PSHIM_HOOKED_OBJECT pHookedOb = g_pObjectCache;
  479. // Dump function map
  480. DPF("ShimLib", eDbgLevelSpew, "\n--- Shim COM Hook Function Map ---\n\n");
  481. while (pMap)
  482. {
  483. DPF("ShimLib", eDbgLevelSpew, "pVtbl: 0x%p pfnNew: 0x%p pfnOld: 0x%p\n",
  484. pMap->pVtbl,
  485. pMap->pfnNew,
  486. pMap->pfnOld);
  487. pMap = (PSHIM_IFACE_FN_MAP) pMap->pNext;
  488. }
  489. // Dump class factory cache
  490. DPF("ShimLib", eDbgLevelSpew, "\n--- Shim Object Cache (SHOULD BE EMPTY!!) ---\n\n");
  491. while (pHookedOb)
  492. {
  493. DPF("ShimLib", eDbgLevelSpew, "pThis: 0x%p dwRef: %d\n",
  494. pHookedOb->pThis,
  495. pHookedOb->dwRef);
  496. pHookedOb = (PSHIM_HOOKED_OBJECT) pHookedOb->pNext;
  497. }
  498. }
  499. /*++
  500. Function Description:
  501. This function adds the object's important info to the object cache and then
  502. patches all required functions. IUnknown is hooked for all objects
  503. regardless.
  504. Arguments:
  505. IN rclsid - CLSID for the class object
  506. IN riid - Reference to the identifier of the interface that communicates
  507. with the class object
  508. OUT ppv - Address of the pThis pointer that uniquely identifies an
  509. instance of the COM interface
  510. OUT pOb - New obj pointer
  511. IN bClassFactory - Is this a class factory call
  512. Return Value:
  513. None
  514. History:
  515. 11/01/1999 markder Created
  516. --*/
  517. VOID
  518. HookObject(
  519. IN CLSID *pCLSID,
  520. IN REFIID riid,
  521. OUT LPVOID *ppv,
  522. OUT PSHIM_HOOKED_OBJECT pOb,
  523. IN BOOL bClassFactory
  524. )
  525. {
  526. // Here's how a COM object looks in memory:
  527. //
  528. // pv - The pointer to the object's interface. In C++ terms, it
  529. // | is sort of like the "this" pointer but objects
  530. // | will hand back different pointers for different interfaces.
  531. // |
  532. // `-> pVtbl - The COM virtual function table pointer. This is the
  533. // | first 32-bit member of the interface structure.
  534. // |
  535. // |-> QueryInterface - First function in the root interface, IUnknown. This
  536. // | function allows calling members to request a different
  537. // | interface that may be implemented by the object.
  538. // |
  539. // |-> AddRef - Increments the reference count for this interface.
  540. // |
  541. // |-> Release - Decrements the reference count for this interface.
  542. // |
  543. // |-> InterfaceFn1 - Beginning of the interface-specific functions.
  544. // |-> InterfaceFn2
  545. // |-> InterfaceFn3
  546. // | .
  547. // | .
  548. // | .
  549. //
  550. // The COM hooking mechanism is interested in the virtual function table pointer, and to get
  551. // it we must dereference the ppv pointer twice.
  552. PVOID *pVtbl = ((PVOID*)(*((PVOID*)(*ppv))));
  553. DWORD i = 0;
  554. if (!pOb)
  555. {
  556. // If pOb is NULL, then the object does not exist in the cache yet.
  557. // Make a new entry for the object.
  558. DPF("ShimLib", eDbgLevelSpew, "[HookObject] New %s! pThis: 0x%p\n",
  559. (bClassFactory?"class factory":"object"),
  560. *ppv);
  561. pOb = (PSHIM_HOOKED_OBJECT) ShimMalloc(sizeof(SHIM_HOOKED_OBJECT));
  562. if( pOb == NULL )
  563. {
  564. DPF("ShimLib", eDbgLevelError, "[HookObject] Could not allocate memory for SHIM_HOOKED_OBJECT.\n");
  565. return;
  566. }
  567. pOb->pCLSID = pCLSID;
  568. pOb->pThis = *ppv;
  569. pOb->dwRef = 1;
  570. pOb->bAddRefTrip = FALSE;
  571. pOb->pNext = g_pObjectCache;
  572. pOb->bClassFactory = bClassFactory;
  573. g_pObjectCache = pOb;
  574. }
  575. // IUnknown must always be hooked since it is possible to get
  576. // a new interface pointer using it, and we need to process each interface
  577. // handed out. We must also keep track of the reference count so that
  578. // we can clean up our interface function map.
  579. PatchFunction(pVtbl, 0, APIHook_QueryInterface);
  580. PatchFunction(pVtbl, 1, APIHook_AddRef);
  581. PatchFunction(pVtbl, 2, APIHook_Release);
  582. if (bClassFactory && IsEqualGUID(IID_IClassFactory, riid))
  583. {
  584. // If we are processing a class factory, all we care about
  585. // hooking is CreateInstance, since it is an API that produces
  586. // the actual object we are interested in.
  587. PatchFunction(pVtbl, 3, APIHook_IClassFactory_CreateInstance);
  588. }
  589. else
  590. {
  591. for (i = 0; i < g_dwCOMHookCount; i++)
  592. {
  593. if (!(g_pCOMHooks[i].pCLSID) || !pCLSID)
  594. {
  595. // A CLSID was not specified -- hook any object that exposes
  596. // the specified interface.
  597. if (IsEqualGUID( (REFIID) *(g_pCOMHooks[i].pIID), riid))
  598. {
  599. PatchFunction(
  600. pVtbl,
  601. g_pCOMHooks[i].dwVtblIndex,
  602. g_pCOMHooks[i].pfnNew);
  603. }
  604. }
  605. else
  606. {
  607. // A CLSID was specified -- hook only interfaces on the
  608. // specified object.
  609. if (IsEqualGUID((REFCLSID) *(g_pCOMHooks[i].pCLSID), *pCLSID) &&
  610. IsEqualGUID((REFIID) *(g_pCOMHooks[i].pIID), riid))
  611. {
  612. PatchFunction(
  613. pVtbl,
  614. g_pCOMHooks[i].dwVtblIndex,
  615. g_pCOMHooks[i].pfnNew);
  616. }
  617. }
  618. }
  619. }
  620. }
  621. BOOL InitHooks(DWORD dwCount)
  622. {
  623. g_dwAPIHookCount = dwCount;
  624. g_pAPIHooks = (PHOOKAPI) ShimMalloc( g_dwAPIHookCount * sizeof(HOOKAPI) );
  625. if (g_pAPIHooks)
  626. {
  627. ZeroMemory(g_pAPIHooks, g_dwAPIHookCount * sizeof(HOOKAPI) );
  628. }
  629. return g_pAPIHooks != NULL;
  630. }
  631. BOOL InitComHooks(DWORD dwCount)
  632. {
  633. //DECLARE_APIHOOK(DDraw.dll, DirectDrawCreate);
  634. //DECLARE_APIHOOK(DDraw.dll, DirectDrawCreateEx);
  635. g_dwCOMHookCount = dwCount;
  636. g_pCOMHooks = (PSHIM_COM_HOOK) ShimMalloc( g_dwCOMHookCount * sizeof(SHIM_COM_HOOK) );
  637. if (g_pCOMHooks)
  638. {
  639. ZeroMemory(g_pCOMHooks, g_dwCOMHookCount * sizeof(SHIM_COM_HOOK) );
  640. }
  641. return g_pCOMHooks != NULL;
  642. }
  643. VOID AddComHook(REFCLSID clsid, REFIID iid, PVOID hook, DWORD vtblndx)
  644. {
  645. if (g_dwCOMHookBuffer <= g_dwCOMHookCount) {
  646. // Buffer is too small, must resize.
  647. DWORD dwNewBuffer = g_dwCOMHookBuffer * 2;
  648. PSHIM_COM_HOOK pNewBuffer = NULL;
  649. if (dwNewBuffer == 0) {
  650. // 50 is the initial allocation, but it should be at least g_dwCOMHookCount
  651. dwNewBuffer = max(50, g_dwCOMHookCount);
  652. }
  653. pNewBuffer = (PSHIM_COM_HOOK) ShimMalloc( sizeof(SHIM_COM_HOOK) * dwNewBuffer );
  654. if (pNewBuffer == NULL) {
  655. DPF("ShimLib", eDbgLevelError,
  656. "[AddComHook] Could not allocate SHIM_COM_HOOK array.");
  657. return;
  658. }
  659. // Copy over original array, then free the old one.
  660. if (g_pCOMHooks != NULL) {
  661. memcpy(pNewBuffer, g_pCOMHooks, sizeof(SHIM_COM_HOOK) * g_dwCOMHookBuffer);
  662. ShimFree(g_pCOMHooks);
  663. }
  664. g_pCOMHooks = pNewBuffer;
  665. g_dwCOMHookBuffer = dwNewBuffer;
  666. }
  667. g_pCOMHooks[g_dwCOMHookCount].pCLSID = (CLSID*) &clsid;
  668. g_pCOMHooks[g_dwCOMHookCount].pIID = (IID*) &iid;
  669. g_pCOMHooks[g_dwCOMHookCount].dwVtblIndex = vtblndx;
  670. g_pCOMHooks[g_dwCOMHookCount].pfnNew = hook;
  671. g_dwCOMHookCount++;
  672. return;
  673. }
  674. }; // end of namespace ShimLib
  675. /*++
  676. Function Description:
  677. Called on process detach with old shim mechanism.
  678. Arguments:
  679. See MSDN
  680. Return Value:
  681. See MSDN
  682. History:
  683. 11/01/1999 markder Created
  684. --*/
  685. BOOL
  686. DllMain(
  687. HINSTANCE hinstDLL,
  688. DWORD fdwReason,
  689. LPVOID /*lpvReserved*/
  690. )
  691. {
  692. using namespace ShimLib;
  693. switch (fdwReason) {
  694. case DLL_PROCESS_ATTACH:
  695. g_hinstDll = hinstDLL;
  696. g_pAPIHooks = NULL;
  697. g_dwAPIHookCount = 0;
  698. g_dwCOMHookCount = 0;
  699. g_dwCOMHookBuffer = 0;
  700. g_pCOMHooks = NULL;
  701. g_pIFaceFnMaps = NULL;
  702. g_pObjectCache = NULL;
  703. g_szCommandLine = "";
  704. g_bMultiShim = FALSE;
  705. g_dwShimVersion = 1;
  706. InitFileLogSupport();
  707. break;
  708. case DLL_PROCESS_DETACH:
  709. if (g_dwCOMHookCount > 0) {
  710. DumpCOMHooks();
  711. }
  712. InitializeHooks(DLL_PROCESS_DETACH);
  713. InitializeHooksEx(DLL_PROCESS_DETACH, NULL, NULL, NULL);
  714. break;
  715. }
  716. return TRUE;
  717. }