Source code of Windows XP (NT5)
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.

987 lines
22 KiB

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