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.

4938 lines
134 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. ShimEng.c
  5. Abstract:
  6. This module implements the shim hooking using IAT thunking. The file
  7. is shared between the Windows2000 and Whistler implementations.
  8. Author:
  9. clupu created 11 July 2000
  10. Revision History:
  11. clupu updated 12 Dec 2000 - one file for both Win2k and Whistler
  12. --*/
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <string.h>
  17. #include <windef.h>
  18. #include <winbase.h>
  19. #include <stdio.h>
  20. #include <apcompat.h>
  21. #include "shimdb.h"
  22. #include "ShimEng.h"
  23. #ifdef SE_WIN2K
  24. #include "NotifyCallback.h"
  25. #endif // SE_WIN2K
  26. #ifndef SE_WIN2K
  27. extern BOOL
  28. LdrInitShimEngineDynamic(
  29. PVOID pShimengModule
  30. );
  31. #endif
  32. BOOL g_bDbgPrintEnabled;
  33. DEBUGLEVEL g_DebugLevel;
  34. //
  35. // The number of SHIMs that can be added dynamically by calling SE_DynamicShim
  36. //
  37. #define MAX_DYNAMIC_SHIMS 128
  38. //
  39. // Flags used in HOOKAPI.dwFlags
  40. //
  41. #define HAF_CHAINED 0x00000004
  42. #define HAF_BOTTOM_OF_CHAIN 0x00000008
  43. //
  44. // Flags used in SHIMINFO.dwFlags
  45. //
  46. #define SIF_RESOLVED 0x00000001
  47. //
  48. // Pipe name for sending messages
  49. //
  50. #define PIPE_NAME L"\\Device\\NamedPipe\\ShimViewer"
  51. typedef struct tagINEXMOD {
  52. char* pszModule;
  53. struct tagINEXMOD* pNext;
  54. } INEXMOD, *PINEXMOD;
  55. typedef enum tagINEX_MODE {
  56. INEX_UNINITIALIZED = 0,
  57. EXCLUDE_SYSTEM32,
  58. EXCLUDE_ALL,
  59. INCLUDE_ALL
  60. } INEX_MODE, *PINEX_MODE;
  61. #define MAX_SHIM_NAME_LEN 63
  62. typedef struct tagSHIMINFO {
  63. DWORD dwHookedAPIs; // the number of APIs hooked by this shim DLL
  64. PVOID pDllBase; // the base address for this shim DLL
  65. DWORD dwFlags; // internal flags
  66. PINEXMOD pFirstInclude; // local inclusion/exclusion list
  67. PINEXMOD pFirstExclude; // local inclusion/exclusion list
  68. INEX_MODE eInExMode; // what inclusion mode are we in?
  69. PLDR_DATA_TABLE_ENTRY pLdrEntry; // pointer to the loader entry for this
  70. // shim DLL.
  71. WCHAR wszName[MAX_SHIM_NAME_LEN + 1]; // name of shim
  72. } SHIMINFO, *PSHIMINFO;
  73. typedef struct tagHOOKEDMODULE {
  74. PVOID pDllBase; // the base address of the loaded module
  75. ULONG ulSizeOfImage; // the size of the DLL image
  76. char szModuleName[128]; // the name of the loaded module
  77. BOOL bInSystem32; // tru if the DLL hooked is in system32
  78. } HOOKEDMODULE, *PHOOKEDMODULE;
  79. //
  80. // The prototypes of the internal stubs.
  81. //
  82. typedef PVOID (*PFNGETPROCADDRESS)(HMODULE hMod, char* pszProc);
  83. typedef HINSTANCE (*PFNLOADLIBRARYA)(LPCSTR lpLibFileName);
  84. typedef HINSTANCE (*PFNLOADLIBRARYW)(LPCWSTR lpLibFileName);
  85. typedef HINSTANCE (*PFNLOADLIBRARYEXA)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
  86. typedef HINSTANCE (*PFNLOADLIBRARYEXW)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
  87. typedef BOOL (*PFNFREELIBRARY)(HMODULE hLibModule);
  88. BOOL
  89. SeiSendDataToPipe(
  90. void
  91. );
  92. #ifdef SE_WIN2K
  93. BOOL PatchNewModules(
  94. BOOL bDynamic
  95. );
  96. #else
  97. BOOL
  98. SeiDisplayAppHelp(
  99. HSDB hSDB,
  100. PSDBQUERYRESULT pSdbQuery
  101. );
  102. #endif // SE_WIN2K
  103. //
  104. // Global function hooks the shim uses to keep from recursing itself
  105. //
  106. PFNRTLALLOCATEHEAP g_pfnRtlAllocateHeap;
  107. PFNRTLFREEHEAP g_pfnRtlFreeHeap;
  108. // Shim's private heap
  109. PVOID g_pShimHeap;
  110. // The global inclusion list.
  111. PINEXMOD g_pGlobalInclusionList = NULL;
  112. // Array with all the HOOKAPI list for all the shim DLLs
  113. PHOOKAPI* g_pHookArray = NULL;
  114. // this variable will only be valid on dynamic cases
  115. HMODULE g_hModule = NULL;
  116. // Internal HOOKAPI for the stubs that the shim engine provides
  117. #define IHA_GetProcAddress 0
  118. #ifdef SE_WIN2K
  119. #define IHA_LoadLibraryA 1
  120. #define IHA_LoadLibraryW 2
  121. #define IHA_LoadLibraryExA 3
  122. #define IHA_LoadLibraryExW 4
  123. #define IHA_FreeLibrary 5
  124. #define IHA_COUNT 6
  125. #else
  126. #define IHA_COUNT 1
  127. #endif // SE_WIN2K
  128. HOOKAPI g_IntHookAPI[IHA_COUNT];
  129. // BUGBUG: comment here
  130. HOOKAPIEX g_IntHookEx[IHA_COUNT];
  131. // Extra info for all the shim DLLs
  132. PSHIMINFO g_pShimInfo;
  133. // The number of all shims applied to this process
  134. DWORD g_dwShimsCount = 0;
  135. // The maximum number of shims that can be applied.
  136. DWORD g_dwMaxShimsCount = 0;
  137. #define SHIM_MAX_HOOKED_MODULES 512
  138. // The array of hooked modules
  139. HOOKEDMODULE g_hHookedModules[SHIM_MAX_HOOKED_MODULES];
  140. // The number of modules hooked
  141. DWORD g_dwHookedModuleCount;
  142. // True if the statically linked modules have been hooked
  143. BOOL g_bShimInitialized = FALSE;
  144. // Don will comment here
  145. BOOL g_bShimDuringInit = FALSE;
  146. #define SHIM_MAX_PATCH_COUNT 64
  147. // The array of in memory patches
  148. PBYTE g_pMemoryPatches[SHIM_MAX_PATCH_COUNT];
  149. // The number of in memory patches
  150. DWORD g_dwMemoryPatchCount;
  151. // This shim engine's module handle
  152. PVOID g_pShimEngModHandle;
  153. // The system32 directory
  154. WCHAR g_szSystem32[MAX_PATH] = L"";
  155. // The length of the System32 directory string;
  156. DWORD g_dwSystem32StrLen = 0;
  157. // The SxS directory
  158. WCHAR g_szSxS[MAX_PATH] = L"";
  159. // The length of the SxS directory string;
  160. DWORD g_dwSxSStrLen = 0;
  161. // The windows directory
  162. WCHAR g_szWindir[MAX_PATH] = L"";
  163. // The exe name for sending data to our named pipe
  164. WCHAR g_szExeName[MAX_PATH] = L"";
  165. // The length of the windows directory string;
  166. DWORD g_dwWindirStrLen = 0;
  167. // Cmd.exe full path
  168. WCHAR g_szCmdExePath[MAX_PATH];
  169. // Are we using an exe entry to get shims from?
  170. BOOL g_bUsingExe;
  171. // Are we using a layer entry to get shims from?
  172. BOOL g_bUsingLayer;
  173. PLDR_DATA_TABLE_ENTRY g_pShimEngLdrEntry;
  174. // This boolean tells if some global vars have been initialized.
  175. BOOL g_bInitGlobals;
  176. // This boolean tells if we shimmed the internal hooks.
  177. BOOL g_bInternalHooksUsed;
  178. // Pipe data
  179. WCHAR g_szPipeData[1024];
  180. #ifndef SE_WIN2K
  181. // The name of the shim DLL that the engine is just about to load.
  182. WCHAR g_wszShimDllInLoading[128];
  183. PVOID g_hApphelpDllHelper;
  184. UNICODE_STRING Kernel32String = RTL_CONSTANT_STRING(L"kernel32.dll");
  185. UNICODE_STRING NtdllString = RTL_CONSTANT_STRING(L"ntdll.dll");
  186. UNICODE_STRING VerifierdllString = RTL_CONSTANT_STRING(L"verifier.dll");
  187. // This tells if the image shimmed is a COM+ image.
  188. BOOL g_bComPlusImage;
  189. #endif // SE_WIN2K
  190. #ifdef DEBUG_SPEW
  191. void
  192. __cdecl
  193. DebugPrintfEx(
  194. DEBUGLEVEL dwDetail,
  195. LPSTR pszFmt,
  196. ...
  197. )
  198. /*++
  199. Return: void
  200. Desc: This function prints debug spew in the debugger.
  201. --*/
  202. {
  203. char szT[1024];
  204. va_list arglist;
  205. int len;
  206. va_start(arglist, pszFmt);
  207. _vsnprintf(szT, 1023, pszFmt, arglist);
  208. szT[1022] = 0;
  209. va_end(arglist);
  210. //
  211. // Make sure we have a '\n' at the end of the string
  212. //
  213. len = strlen(szT);
  214. if (szT[len - 1] != '\n') {
  215. strcpy(szT + len, "\n");
  216. }
  217. if (dwDetail <= g_DebugLevel) {
  218. switch (dwDetail) {
  219. case dlPrint:
  220. DbgPrint("[MSG ] ");
  221. break;
  222. case dlError:
  223. DbgPrint("[FAIL] ");
  224. break;
  225. case dlWarning:
  226. DbgPrint("[WARN] ");
  227. break;
  228. case dlInfo:
  229. DbgPrint("[INFO] ");
  230. break;
  231. }
  232. DbgPrint("%s", szT);
  233. }
  234. }
  235. void
  236. SeiInitDebugSupport(
  237. void
  238. )
  239. /*++
  240. Return: void
  241. Desc: This function initializes g_bDbgPrintEnabled based on an env variable.
  242. --*/
  243. {
  244. NTSTATUS status;
  245. UNICODE_STRING EnvName;
  246. UNICODE_STRING EnvValue;
  247. WCHAR wszEnvValue[128];
  248. RtlInitUnicodeString(&EnvName, L"SHIMENG_DEBUG_LEVEL");
  249. EnvValue.Buffer = wszEnvValue;
  250. EnvValue.Length = 0;
  251. EnvValue.MaximumLength = sizeof(wszEnvValue);
  252. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  253. if (NT_SUCCESS(status)) {
  254. WCHAR c = EnvValue.Buffer[0];
  255. g_bDbgPrintEnabled = TRUE;
  256. switch (c) {
  257. case L'0':
  258. g_DebugLevel = dlNone;
  259. g_bDbgPrintEnabled = FALSE;
  260. break;
  261. case L'1':
  262. g_DebugLevel = dlPrint;
  263. break;
  264. case L'2':
  265. g_DebugLevel = dlError;
  266. break;
  267. case L'3':
  268. g_DebugLevel = dlWarning;
  269. break;
  270. case L'4':
  271. default:
  272. g_DebugLevel = dlInfo;
  273. break;
  274. }
  275. }
  276. }
  277. #endif // DEBUG_SPEW
  278. PHOOKAPI
  279. SeiConstructChain(
  280. IN PVOID pfnOld, // Original API function pointer to resolve.
  281. OUT DWORD* pdwDllIndex // Will receive the index of the shim DLL
  282. // that provides the returning PHOOKAPI.
  283. )
  284. /*++
  285. Return: Top-of-chain PHOOKAPI structure.
  286. Desc: Scans HOOKAPI arrays for pfnOld and either constructs the
  287. chain or returns the top-of-chain PHOOKAPI if the chain
  288. already exists.
  289. --*/
  290. {
  291. LONG i; // use LONG because we decrement this and compare it for positive
  292. DWORD j;
  293. PHOOKAPI pTopHookAPI = NULL;
  294. PHOOKAPI pBottomHookAPI = NULL;
  295. *pdwDllIndex = 0;
  296. //
  297. // Scan all HOOKAPI entries for corresponding function pointer.
  298. //
  299. for (i = (LONG)g_dwShimsCount - 1; i >= 0; i--) {
  300. for (j = 0; j < g_pShimInfo[i].dwHookedAPIs; j++) {
  301. if (g_pHookArray[i][j].pfnOld == pfnOld) {
  302. if (pTopHookAPI != NULL) {
  303. //
  304. // The chain has already begun, so tack this one on
  305. // to the end.
  306. //
  307. pBottomHookAPI->pfnOld = g_pHookArray[i][j].pfnNew;
  308. if (pBottomHookAPI->pHookEx) {
  309. pBottomHookAPI->pHookEx->pNext = &(g_pHookArray[i][j]);
  310. }
  311. pBottomHookAPI = &(g_pHookArray[i][j]);
  312. if (pBottomHookAPI->pHookEx) {
  313. pBottomHookAPI->pHookEx->pTopOfChain = pTopHookAPI;
  314. }
  315. pBottomHookAPI->dwFlags |= HAF_CHAINED;
  316. DPF(dlInfo, " 0x%p ->", pBottomHookAPI->pfnNew);
  317. } else {
  318. //
  319. // This is the top of the chain. The inclusion/exclusion list
  320. // from the DLL at the top of the chain is used to determine if
  321. // an import entry in a particular DLL is hooked or not.
  322. // See SeiHookImports for use of pdwIndex.
  323. //
  324. *pdwDllIndex = i;
  325. if (g_pHookArray[i][j].pHookEx && g_pHookArray[i][j].pHookEx->pTopOfChain) {
  326. //
  327. // Chain has already been constructed.
  328. //
  329. return g_pHookArray[i][j].pHookEx->pTopOfChain;
  330. }
  331. //
  332. // Not hooked yet. Set to top of chain.
  333. //
  334. pTopHookAPI = &(g_pHookArray[i][j]);
  335. if (pTopHookAPI->pHookEx) {
  336. pTopHookAPI->pHookEx->pTopOfChain = pTopHookAPI;
  337. }
  338. pTopHookAPI->dwFlags |= HAF_CHAINED;
  339. pBottomHookAPI = pTopHookAPI;
  340. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  341. DPF(dlInfo, "[SeiConstructChain] %s!#%d 0x%p ->",
  342. pTopHookAPI->pszModule,
  343. pTopHookAPI->pszFunctionName,
  344. pTopHookAPI->pfnNew);
  345. } else {
  346. DPF(dlInfo, "[SeiConstructChain] %s!%-20s 0x%p ->",
  347. pTopHookAPI->pszModule,
  348. pTopHookAPI->pszFunctionName,
  349. pTopHookAPI->pfnNew);
  350. }
  351. }
  352. }
  353. }
  354. }
  355. if (pBottomHookAPI != NULL) {
  356. pBottomHookAPI->dwFlags |= HAF_BOTTOM_OF_CHAIN;
  357. DPF(dlInfo, " 0x%p\n", pBottomHookAPI->pfnOld);
  358. }
  359. return pTopHookAPI;
  360. }
  361. PVOID
  362. SeiGetPatchAddress(
  363. IN PRELATIVE_MODULE_ADDRESS pRelAddress // A RELATIVE_MODULE_ADDRESS structure
  364. // that defines the memory location as
  365. // an offset from a loaded module.
  366. )
  367. /*++
  368. Return: The actual memory address of the specified module + offset.
  369. Desc: Resolves a RELATIVE_MODULE_ADDRESS structure into an actual memory address.
  370. --*/
  371. {
  372. WCHAR wszModule[MAX_PATH];
  373. PVOID ModuleHandle = NULL;
  374. UNICODE_STRING UnicodeString;
  375. NTSTATUS status;
  376. PPEB Peb = NtCurrentPeb();
  377. if (pRelAddress->moduleName[0] != 0) {
  378. //
  379. // Copy the module name from the patch since it will typically be misaligned.
  380. //
  381. wcscpy(wszModule, pRelAddress->moduleName);
  382. RtlInitUnicodeString(&UnicodeString, wszModule);
  383. //
  384. // Make sure the module is loaded before calculating address ranges.
  385. //
  386. status = LdrGetDllHandle(NULL, NULL, &UnicodeString, &ModuleHandle);
  387. if (!NT_SUCCESS(status)) {
  388. DPF(dlWarning,
  389. "[SeiGetPatchAddress] Dll \"%S\" not yet loaded for memory patching.\n",
  390. wszModule);
  391. return NULL;
  392. }
  393. //
  394. // We're done, return the address
  395. //
  396. return (PVOID)((ULONG_PTR)ModuleHandle + (ULONG_PTR)pRelAddress->address);
  397. }
  398. //
  399. // This patch is for the main EXE.
  400. //
  401. return (PVOID)((ULONG_PTR)Peb->ImageBaseAddress + (ULONG_PTR)pRelAddress->address);
  402. }
  403. int
  404. SeiApplyPatch(
  405. IN PBYTE pPatch // A patch code blob.
  406. )
  407. /*++
  408. Return: 1 for success, 0 for failure.
  409. Desc: Attempts to execute all commands in a patch code blob. If DLLs are not loaded,
  410. this function will return 0.
  411. --*/
  412. {
  413. PPATCHMATCHDATA pMatchData;
  414. PPATCHWRITEDATA pWriteData;
  415. PPATCHOP pPatchOP;
  416. NTSTATUS status;
  417. PVOID pAddress;
  418. PVOID pProtectFuncAddress = NULL;
  419. SIZE_T dwProtectSize = 0;
  420. DWORD dwOldFlags = 0;
  421. //
  422. // Grab the opcode and see what we have to do.
  423. //
  424. while (TRUE) {
  425. pPatchOP = (PPATCHOP)pPatch;
  426. switch (pPatchOP->dwOpcode) {
  427. case PEND:
  428. return 1;
  429. case PWD:
  430. //
  431. // This is a patch write data primitive - write the data.
  432. //
  433. pWriteData = (PPATCHWRITEDATA)pPatchOP->data;
  434. //
  435. // Grab the physical address to do this operation.
  436. //
  437. pAddress = SeiGetPatchAddress(&(pWriteData->rva));
  438. if (pAddress == NULL) {
  439. DPF(dlWarning, "[SeiApplyPatch] DLL not loaded for memory patching.\n");
  440. return 0;
  441. }
  442. //
  443. // Fixup the page attributes.
  444. //
  445. dwProtectSize = pWriteData->dwSizeData;
  446. pProtectFuncAddress = pAddress;
  447. status = NtProtectVirtualMemory(NtCurrentProcess(),
  448. (PVOID)&pProtectFuncAddress,
  449. &dwProtectSize,
  450. PAGE_READWRITE,
  451. &dwOldFlags);
  452. if (!NT_SUCCESS(status)) {
  453. DPF(dlError, "[SeiApplyPatch] NtProtectVirtualMemory failed 0x%X.\n",
  454. status);
  455. return 0;
  456. }
  457. //
  458. // Copy the patch bytes.
  459. //
  460. RtlCopyMemory((PVOID)pAddress, (PVOID)pWriteData->data, pWriteData->dwSizeData);
  461. //
  462. // Restore the page protection.
  463. //
  464. dwProtectSize = pWriteData->dwSizeData;
  465. pProtectFuncAddress = pAddress;
  466. status = NtProtectVirtualMemory(NtCurrentProcess(),
  467. (PVOID)&pProtectFuncAddress,
  468. &dwProtectSize,
  469. dwOldFlags,
  470. &dwOldFlags);
  471. if (!NT_SUCCESS(status)) {
  472. DPF(dlError, "[SeiApplyPatch] NtProtectVirtualMemory failed 0x%X.\n",
  473. status);
  474. return 0;
  475. }
  476. status = NtFlushInstructionCache(NtCurrentProcess(),
  477. pProtectFuncAddress,
  478. dwProtectSize);
  479. if (!NT_SUCCESS(status)) {
  480. DPF(dlError,
  481. "[SeiApplyPatch] NtFlushInstructionCache failed w/ status 0x%X.\n",
  482. status);
  483. }
  484. break;
  485. case PMAT:
  486. //
  487. // This is a patch match data at offset primitive.
  488. //
  489. pMatchData = (PPATCHMATCHDATA)pPatchOP->data;
  490. //
  491. // Grab the physical address to do this operation
  492. //
  493. pAddress = SeiGetPatchAddress(&(pMatchData->rva));
  494. if (pAddress == NULL) {
  495. DPF(dlWarning, "[SeiApplyPatch] SeiGetPatchAddress failed.\n");
  496. return 0;
  497. }
  498. //
  499. // Make sure there is a match with what we expect to be there.
  500. //
  501. if (!RtlEqualMemory(pMatchData->data, (PBYTE)pAddress, pMatchData->dwSizeData)) {
  502. DPF(dlError, "[SeiApplyPatch] Failure matching on patch data.\n");
  503. return 0;
  504. }
  505. break;
  506. default:
  507. //
  508. // If this happens we got an unexpected operation and we have to fail.
  509. //
  510. DPF(dlError, "[SeiApplyPatch] Unknown patch opcode 0x%X.\n",
  511. pPatchOP->dwOpcode);
  512. ASSERT(0);
  513. return 0;
  514. }
  515. //
  516. // Next opcode.
  517. //
  518. pPatch = (PBYTE)(pPatchOP->dwNextOpcode + pPatch);
  519. }
  520. return 1;
  521. }
  522. void
  523. SeiAttemptPatches(
  524. void
  525. )
  526. /*++
  527. Return: void.
  528. Desc: Attempts all patches in the global array.
  529. --*/
  530. {
  531. DWORD i, dwSucceeded = 0;
  532. for (i = 0; i < g_dwMemoryPatchCount; i++) {
  533. dwSucceeded += SeiApplyPatch(g_pMemoryPatches[i]);
  534. }
  535. if (g_dwMemoryPatchCount > 0) {
  536. DPF(dlInfo, "[SeiAttemptPatches] Applied %d of %d patches.\n",
  537. dwSucceeded,
  538. g_dwMemoryPatchCount);
  539. swprintf(g_szPipeData, L"%s - Applied %d of %d patches",
  540. g_szExeName,
  541. dwSucceeded,
  542. g_dwMemoryPatchCount);
  543. SeiSendDataToPipe();
  544. }
  545. }
  546. void
  547. SeiResolveAPIs(
  548. void
  549. )
  550. /*++
  551. Return: void
  552. Desc: Loops through the array of HOOKAPI and sets pfnOld if it wasn't
  553. already set.
  554. --*/
  555. {
  556. DWORD i, j;
  557. ANSI_STRING AnsiString;
  558. UNICODE_STRING UnicodeString;
  559. WCHAR wszBuffer[MAX_PATH];
  560. STRING ProcedureNameString;
  561. PVOID pfnOld;
  562. PVOID ModuleHandle = NULL;
  563. NTSTATUS status;
  564. BOOL bAllApisResolved;
  565. char* pszFunctionName;
  566. UnicodeString.Buffer = wszBuffer;
  567. for (i = 0; i < g_dwShimsCount; i++) {
  568. //
  569. // See if we've already resolved all the APIs this shim DLL wanted to hook.
  570. //
  571. if (g_pShimInfo[i].dwFlags & SIF_RESOLVED) {
  572. continue;
  573. }
  574. bAllApisResolved = TRUE;
  575. for (j = 0; j < g_pShimInfo[i].dwHookedAPIs; j++) {
  576. //
  577. // Ignore resolved APIs.
  578. //
  579. if (g_pHookArray[i][j].pfnOld != NULL) {
  580. continue;
  581. }
  582. //
  583. // Don't try to load unspecified modules.
  584. //
  585. if (g_pHookArray[i][j].pszModule == NULL) {
  586. continue;
  587. }
  588. //
  589. // Is this DLL mapped in the address space?
  590. //
  591. RtlInitAnsiString(&AnsiString, g_pHookArray[i][j].pszModule);
  592. UnicodeString.MaximumLength = sizeof(wszBuffer);
  593. if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString,
  594. &AnsiString,
  595. FALSE))){
  596. DPF(dlError,
  597. "[SeiResolveAPIs] Failed to convert string \"%s\" to UNICODE.\n",
  598. g_pHookArray[i][j].pszModule);
  599. continue;
  600. }
  601. status = LdrGetDllHandle(NULL,
  602. NULL,
  603. &UnicodeString,
  604. &ModuleHandle);
  605. if (!NT_SUCCESS(status)) {
  606. bAllApisResolved = FALSE;
  607. continue;
  608. }
  609. //
  610. // Get the original entry point for this hook.
  611. //
  612. pszFunctionName = g_pHookArray[i][j].pszFunctionName;
  613. if ((ULONG_PTR)pszFunctionName < 0x0000FFFF) {
  614. status = LdrGetProcedureAddress(ModuleHandle,
  615. NULL,
  616. (ULONG)(ULONG_PTR)pszFunctionName,
  617. &pfnOld);
  618. } else {
  619. RtlInitString(&ProcedureNameString, pszFunctionName);
  620. status = LdrGetProcedureAddress(ModuleHandle,
  621. &ProcedureNameString,
  622. 0,
  623. &pfnOld);
  624. }
  625. if (!NT_SUCCESS(status) || pfnOld == NULL) {
  626. bAllApisResolved = FALSE;
  627. if ((ULONG_PTR)pszFunctionName < 0x0000FFFF) {
  628. DPF(dlError, "[SeiResolveAPIs] There is no \"%s!#%d\" !\n",
  629. g_pHookArray[i][j].pszModule,
  630. pszFunctionName);
  631. } else {
  632. DPF(dlError, "[SeiResolveAPIs] There is no \"%s!%s\" !\n",
  633. g_pHookArray[i][j].pszModule,
  634. pszFunctionName);
  635. }
  636. continue;
  637. }
  638. g_pHookArray[i][j].pfnOld = pfnOld;
  639. if ((ULONG_PTR)pszFunctionName < 0x0000FFFF) {
  640. DPF(dlInfo, "[SeiResolveAPIs] Resolved \"%s!#%d\" to 0x%p\n",
  641. g_pHookArray[i][j].pszModule,
  642. pszFunctionName,
  643. pfnOld);
  644. } else {
  645. DPF(dlInfo, "[SeiResolveAPIs] Resolved \"%s!%s\" to 0x%p\n",
  646. g_pHookArray[i][j].pszModule,
  647. pszFunctionName,
  648. pfnOld);
  649. }
  650. }
  651. //
  652. // See if all the APIs were resolved for this shim DLL.
  653. //
  654. if (bAllApisResolved) {
  655. g_pShimInfo[i].dwFlags |= SIF_RESOLVED;
  656. }
  657. }
  658. }
  659. BOOL
  660. SeiIsExcluded(
  661. IN LPCSTR pszModule, // The module to test for exclusion.
  662. IN PHOOKAPI pTopHookAPI, // The HOOKAPI for which we test for exclusion.
  663. IN BOOL bInSystem32 // Whether the module is located in the System32 directory.
  664. )
  665. /*++
  666. Return: TRUE if the requested module shouldn't be patched.
  667. Desc: Checks the inclusion/exclusion list of the shim DLL specified by
  668. dwCounter and then checks the global exclusion list also.
  669. --*/
  670. {
  671. BOOL bExclude = TRUE;
  672. BOOL bShimWantsToExclude = FALSE; // was there a shim that wanted to exclude?
  673. PHOOKAPI pHook = pTopHookAPI;
  674. //
  675. // The current process is to only exclude a chain if every shim in the chain wants to
  676. // exclude. If one shim needs to be included, the whole chain is included.
  677. //
  678. while (pHook && pHook->pHookEx) {
  679. DWORD dwCounter;
  680. dwCounter = pHook->pHookEx->dwShimID;
  681. switch (g_pShimInfo[dwCounter].eInExMode) {
  682. case INCLUDE_ALL:
  683. {
  684. //
  685. // We include everything except what's in the exclude list.
  686. //
  687. PINEXMOD pExcludeMod;
  688. pExcludeMod = g_pShimInfo[dwCounter].pFirstExclude;
  689. while (pExcludeMod != NULL) {
  690. if (_stricmp(pExcludeMod->pszModule, pszModule) == 0) {
  691. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  692. DPF(dlInfo,
  693. "[SeiIsExcluded] Module \"%s\" excluded for shim %S, API \"%s!#%d\", because it is in the exclude list (MODE: IA).\n",
  694. pszModule,
  695. g_pShimInfo[dwCounter].wszName,
  696. pTopHookAPI->pszModule,
  697. pTopHookAPI->pszFunctionName);
  698. } else {
  699. DPF(dlInfo,
  700. "[SeiIsExcluded] Module \"%s\" excluded for shim %S, API \"%s!%s\", because it is in the exclude list (MODE: IA).\n",
  701. pszModule,
  702. g_pShimInfo[dwCounter].wszName,
  703. pTopHookAPI->pszModule,
  704. pTopHookAPI->pszFunctionName);
  705. }
  706. //
  707. // this wants to be excluded, so we go to the next
  708. // shim, and see if it wants to be included
  709. //
  710. bShimWantsToExclude = TRUE;
  711. goto nextShim;
  712. }
  713. pExcludeMod = pExcludeMod->pNext;
  714. }
  715. //
  716. // we should include this shim, and therefore, the whole chain
  717. //
  718. bExclude = FALSE;
  719. goto out;
  720. break;
  721. }
  722. case EXCLUDE_SYSTEM32:
  723. {
  724. //
  725. // In this case, we first check the include list,
  726. // then exclude it if it's in System32, then exclude it if
  727. // it's in the exclude list.
  728. //
  729. PINEXMOD pIncludeMod;
  730. PINEXMOD pExcludeMod;
  731. pIncludeMod = g_pShimInfo[dwCounter].pFirstInclude;
  732. pExcludeMod = g_pShimInfo[dwCounter].pFirstExclude;
  733. //
  734. // First, check the include list.
  735. //
  736. while (pIncludeMod != NULL) {
  737. if (_stricmp(pIncludeMod->pszModule, pszModule) == 0) {
  738. //
  739. // we should include this shim, and therefore, the whole chain
  740. //
  741. bExclude = FALSE;
  742. goto out;
  743. }
  744. pIncludeMod = pIncludeMod->pNext;
  745. }
  746. //
  747. // it wasn't in the include list, so is it in System32?
  748. //
  749. if (bInSystem32) {
  750. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  751. DPF(dlInfo,
  752. "[SeiIsExcluded] module \"%s\" excluded for shim %S, API \"%s!#%d\", because it is in System32.\n",
  753. pszModule,
  754. g_pShimInfo[dwCounter].wszName,
  755. pTopHookAPI->pszModule,
  756. pTopHookAPI->pszFunctionName);
  757. } else {
  758. DPF(dlInfo,
  759. "[SeiIsExcluded] module \"%s\" excluded for shim %S, API \"%s!%s\", because it is in System32.\n",
  760. pszModule,
  761. g_pShimInfo[dwCounter].wszName,
  762. pTopHookAPI->pszModule,
  763. pTopHookAPI->pszFunctionName);
  764. }
  765. //
  766. // this wants to be excluded, so we go to the next
  767. // shim, and see if it wants to be included
  768. //
  769. bShimWantsToExclude = TRUE;
  770. goto nextShim;
  771. }
  772. //
  773. // it wasn't in System32, so is it in the exclude list?
  774. //
  775. while (pExcludeMod != NULL) {
  776. if (_stricmp(pExcludeMod->pszModule, pszModule) == 0) {
  777. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  778. DPF(dlInfo,
  779. "[SeiIsExcluded] module \"%s\" excluded for shim %S, API \"%s!#%d\", because it is in the exclude list (MODE: ES).\n",
  780. pszModule,
  781. g_pShimInfo[dwCounter].wszName,
  782. pTopHookAPI->pszModule,
  783. pTopHookAPI->pszFunctionName);
  784. } else {
  785. DPF(dlInfo,
  786. "[SeiIsExcluded] module \"%s\" excluded for shim %S, API \"%s!%s\", because it is in the exclude list (MODE: ES).\n",
  787. pszModule,
  788. g_pShimInfo[dwCounter].wszName,
  789. pTopHookAPI->pszModule,
  790. pTopHookAPI->pszFunctionName);
  791. }
  792. //
  793. // this wants to be excluded, so we go to the next
  794. // shim, and see if it wants to be included
  795. //
  796. bShimWantsToExclude = TRUE;
  797. goto nextShim;
  798. }
  799. pExcludeMod = pExcludeMod->pNext;
  800. }
  801. //
  802. // we should include this shim, and therefore, the whole chain
  803. //
  804. bExclude = FALSE;
  805. goto out;
  806. break;
  807. }
  808. case EXCLUDE_ALL:
  809. {
  810. //
  811. // We exclude everything except what is in the include list.
  812. //
  813. PINEXMOD pIncludeMod;
  814. pIncludeMod = g_pShimInfo[dwCounter].pFirstInclude;
  815. while (pIncludeMod != NULL) {
  816. if (_stricmp(pIncludeMod->pszModule, pszModule) == 0) {
  817. //
  818. // we should include this shim, and therefore, the whole chain
  819. //
  820. bExclude = FALSE;
  821. goto out;
  822. }
  823. pIncludeMod = pIncludeMod->pNext;
  824. }
  825. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  826. DPF(dlInfo,
  827. "[SeiIsExcluded] module \"%s\" excluded for shim %S, API \"%s!#%d\", because it is not in the include list (MODE: EA).\n",
  828. pszModule,
  829. g_pShimInfo[dwCounter].wszName,
  830. pTopHookAPI->pszModule,
  831. pTopHookAPI->pszFunctionName);
  832. } else {
  833. DPF(dlInfo,
  834. "[SeiIsExcluded] module \"%s\" excluded for shim %S, API \"%s!%s\", because it is not in the include list (MODE: EA).\n",
  835. pszModule,
  836. g_pShimInfo[dwCounter].wszName,
  837. pTopHookAPI->pszModule,
  838. pTopHookAPI->pszFunctionName);
  839. }
  840. //
  841. // this wants to be excluded, so we go to the next
  842. // shim, and see if it wants to be included
  843. //
  844. bShimWantsToExclude = TRUE;
  845. goto nextShim;
  846. break;
  847. }
  848. }
  849. nextShim:
  850. pHook = pHook->pHookEx->pNext;
  851. }
  852. out:
  853. if (!bExclude && bShimWantsToExclude) {
  854. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  855. DPF(dlError,
  856. "[SeiIsExcluded] Module \"%s\" mixed inclusion/exclusion for "
  857. "API \"%s!#%d\". Included.\n",
  858. pszModule,
  859. pTopHookAPI->pszModule,
  860. pTopHookAPI->pszFunctionName);
  861. } else {
  862. DPF(dlError,
  863. "[SeiIsExcluded] Module \"%s\" mixed inclusion/exclusion for "
  864. "API \"%s!%s\". Included.\n",
  865. pszModule,
  866. pTopHookAPI->pszModule,
  867. pTopHookAPI->pszFunctionName);
  868. }
  869. }
  870. return bExclude;
  871. }
  872. BOOL
  873. SeiHookImports(
  874. IN PBYTE pDllBase, // The base address of the DLL to be hooked
  875. IN ULONG ulSizeOfImage, // The size of the DLL image
  876. IN PUNICODE_STRING pstrDllName, // The name of the DLL to be hooked
  877. IN BOOL bInSystem32 // TRUE if this is a system32 DLL
  878. )
  879. /*++
  880. Return: TRUE if successful.
  881. Desc: Walks the import table of the specified module and patches the APIs
  882. that need to be hooked.
  883. --*/
  884. {
  885. CHAR szBaseDllName[MAX_PATH];
  886. ANSI_STRING AnsiString = { 0, sizeof(szBaseDllName), szBaseDllName };
  887. NTSTATUS status;
  888. BOOL bAnyHooked = FALSE;
  889. PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER)pDllBase;
  890. PIMAGE_NT_HEADERS pINTH;
  891. PIMAGE_IMPORT_DESCRIPTOR pIID;
  892. DWORD dwImportTableOffset;
  893. PHOOKAPI pTopHookAPI;
  894. DWORD dwOldProtect, dwOldProtect2;
  895. SIZE_T dwProtectSize;
  896. DWORD i, j;
  897. PVOID pfnOld;
  898. status = RtlUnicodeStringToAnsiString(&AnsiString, pstrDllName, FALSE);
  899. if (!NT_SUCCESS(status)) {
  900. DPF(dlError, "[SeiHookImports] Cannot convert \"%S\" to ANSI\n",
  901. pstrDllName->Buffer);
  902. return FALSE;
  903. }
  904. //
  905. // Get the import table.
  906. //
  907. pINTH = (PIMAGE_NT_HEADERS)(pDllBase + pIDH->e_lfanew);
  908. dwImportTableOffset = pINTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  909. if (dwImportTableOffset == 0) {
  910. //
  911. // No import table found. This is probably ntdll.dll
  912. //
  913. return TRUE;
  914. }
  915. DPF(dlInfo, "[SeiHookImports] Hooking module 0x%p \"%s\"\n", pDllBase, szBaseDllName);
  916. pIID = (PIMAGE_IMPORT_DESCRIPTOR)(pDllBase + dwImportTableOffset);
  917. //
  918. // Loop through the import table and search for the APIs that we want to patch
  919. //
  920. while (TRUE) {
  921. LPSTR pszImportEntryModule;
  922. PIMAGE_THUNK_DATA pITDA;
  923. //
  924. // Return if no first thunk (terminating condition).
  925. //
  926. if (pIID->FirstThunk == 0) {
  927. break;
  928. }
  929. pszImportEntryModule = (LPSTR)(pDllBase + pIID->Name);
  930. //
  931. // If we're not interested in this module jump to the next.
  932. //
  933. bAnyHooked = FALSE;
  934. for (i = 0; i < g_dwShimsCount; i++) {
  935. for (j = 0; j < g_pShimInfo[i].dwHookedAPIs; j++) {
  936. if (g_pHookArray[i][j].pszModule != NULL &&
  937. _stricmp(g_pHookArray[i][j].pszModule, pszImportEntryModule) == 0) {
  938. bAnyHooked = TRUE;
  939. goto ScanDone;
  940. }
  941. }
  942. }
  943. ScanDone:
  944. if (!bAnyHooked) {
  945. pIID++;
  946. continue;
  947. }
  948. //
  949. // We have APIs to hook for this module!
  950. //
  951. pITDA = (PIMAGE_THUNK_DATA)(pDllBase + (DWORD)pIID->FirstThunk);
  952. while (TRUE) {
  953. SIZE_T dwFuncAddr;
  954. pfnOld = (PVOID)pITDA->u1.Function;
  955. //
  956. // Done with all the imports from this module? (terminating condition)
  957. //
  958. if (pITDA->u1.Ordinal == 0) {
  959. break;
  960. }
  961. pTopHookAPI = SeiConstructChain(pfnOld, &i);
  962. if (pTopHookAPI == NULL || SeiIsExcluded(szBaseDllName, pTopHookAPI, bInSystem32)) {
  963. pITDA++;
  964. continue;
  965. }
  966. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  967. DPF(dlInfo,
  968. "[SeiHookImports] Hooking API \"%s!#%d\" for DLL \"%s\"\n",
  969. pTopHookAPI->pszModule,
  970. pTopHookAPI->pszFunctionName,
  971. szBaseDllName);
  972. } else {
  973. DPF(dlInfo,
  974. "[SeiHookImports] Hooking API \"%s!%s\" for DLL \"%s\"\n",
  975. pTopHookAPI->pszModule,
  976. pTopHookAPI->pszFunctionName,
  977. szBaseDllName);
  978. }
  979. //
  980. // Make the code page writable and overwrite new function pointer
  981. // in the import table.
  982. //
  983. dwProtectSize = sizeof(DWORD);
  984. dwFuncAddr = (SIZE_T)&pITDA->u1.Function;
  985. status = NtProtectVirtualMemory(NtCurrentProcess(),
  986. (PVOID)&dwFuncAddr,
  987. &dwProtectSize,
  988. PAGE_READWRITE,
  989. &dwOldProtect);
  990. if (NT_SUCCESS(status)) {
  991. pITDA->u1.Function = (SIZE_T)pTopHookAPI->pfnNew;
  992. dwProtectSize = sizeof(DWORD);
  993. status = NtProtectVirtualMemory(NtCurrentProcess(),
  994. (PVOID)&dwFuncAddr,
  995. &dwProtectSize,
  996. dwOldProtect,
  997. &dwOldProtect2);
  998. if (!NT_SUCCESS(status)) {
  999. DPF(dlError, "[SeiHookImports] Failed to change back the protection\n");
  1000. }
  1001. } else {
  1002. DPF(dlError,
  1003. "[SeiHookImports] Failed 0x%X to change protection to PAGE_READWRITE."
  1004. " Addr 0x%p\n",
  1005. status,
  1006. &pITDA->u1.Function);
  1007. }
  1008. pITDA++;
  1009. }
  1010. pIID++;
  1011. }
  1012. //
  1013. // Add the hooked module to the list of hooked modules
  1014. //
  1015. g_hHookedModules[g_dwHookedModuleCount].pDllBase = pDllBase;
  1016. g_hHookedModules[g_dwHookedModuleCount].ulSizeOfImage = ulSizeOfImage;
  1017. g_hHookedModules[g_dwHookedModuleCount].bInSystem32 = bInSystem32;
  1018. strcpy(g_hHookedModules[g_dwHookedModuleCount++].szModuleName, szBaseDllName);
  1019. return TRUE;
  1020. }
  1021. //
  1022. // NOTE: This used to be an exported function in the Win2k shim engine so
  1023. // let's not change its name.
  1024. //
  1025. BOOL
  1026. PatchNewModules(
  1027. BOOL bDynamic
  1028. )
  1029. /*++
  1030. Return: STATUS_SUCCESS if successful
  1031. Desc: Walks the loader list of loaded modules and attempts to patch all
  1032. the modules that are not already patched. It also attempts to
  1033. install the in memory patches.
  1034. --*/
  1035. {
  1036. PPEB Peb = NtCurrentPeb();
  1037. PLIST_ENTRY LdrHead;
  1038. PLIST_ENTRY LdrNext;
  1039. DWORD i;
  1040. BOOL bInSystem32;
  1041. //
  1042. // Resolve any APIs that became available from newly loaded modules.
  1043. //
  1044. SeiResolveAPIs();
  1045. if (g_bShimInitialized) {
  1046. DPF(dlInfo, "[PatchNewModules] Dynamic loaded modules\n");
  1047. }
  1048. //
  1049. // Try to apply memory patches.
  1050. //
  1051. SeiAttemptPatches();
  1052. //
  1053. // Return if only patches were required.
  1054. //
  1055. if (g_dwShimsCount == 0) {
  1056. return TRUE;
  1057. }
  1058. //
  1059. // Loop through the loaded modules
  1060. //
  1061. LdrHead = &Peb->Ldr->InMemoryOrderModuleList;
  1062. LdrNext = LdrHead->Flink;
  1063. while (LdrNext != LdrHead) {
  1064. PLDR_DATA_TABLE_ENTRY LdrEntry;
  1065. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  1066. if ((SSIZE_T)LdrEntry->DllBase < 0) {
  1067. DPF(dlWarning, "[PatchNewModules] Not hooking kernel-mode DLL \"%S\"\n",
  1068. LdrEntry->BaseDllName.Buffer);
  1069. goto Continue;
  1070. }
  1071. //
  1072. // Don't hook our shim DLLs!
  1073. //
  1074. for (i = 0; i < g_dwShimsCount; i++) {
  1075. if (g_pShimInfo[i].pDllBase == LdrEntry->DllBase) {
  1076. goto Continue;
  1077. }
  1078. }
  1079. //
  1080. // Don't hook the shim engine!
  1081. //
  1082. if (LdrEntry->DllBase == g_pShimEngModHandle) {
  1083. goto Continue;
  1084. }
  1085. //
  1086. // Do nothing if it's already hooked.
  1087. //
  1088. if (!bDynamic) {
  1089. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1090. if (LdrEntry->DllBase == g_hHookedModules[i].pDllBase) {
  1091. goto Continue;
  1092. }
  1093. }
  1094. }
  1095. //
  1096. // Make sure we're not hooking more DLLs than we can.
  1097. //
  1098. if (g_dwHookedModuleCount == SHIM_MAX_HOOKED_MODULES - 1) {
  1099. DPF(dlError, "\n[PatchNewModules] Too many modules hooked!!!\n\n");
  1100. ASSERT(g_dwHookedModuleCount < SHIM_MAX_HOOKED_MODULES - 1);
  1101. break;
  1102. }
  1103. //
  1104. // Check if this DLL is in System32 (or WinSxS), and hence a possible candidate for blanket
  1105. // exclusion.
  1106. //
  1107. if ((g_dwSystem32StrLen && _wcsnicmp(g_szSystem32,
  1108. LdrEntry->FullDllName.Buffer, g_dwSystem32StrLen) == 0) ||
  1109. (g_dwSxSStrLen && _wcsnicmp(g_szSxS,
  1110. LdrEntry->FullDllName.Buffer, g_dwSxSStrLen) == 0)) {
  1111. bInSystem32 = TRUE;
  1112. } else {
  1113. bInSystem32 = FALSE;
  1114. }
  1115. //
  1116. // This is a candidate for hooking.
  1117. //
  1118. SeiHookImports(LdrEntry->DllBase,
  1119. LdrEntry->SizeOfImage,
  1120. &LdrEntry->BaseDllName,
  1121. bInSystem32);
  1122. Continue:
  1123. LdrNext = LdrEntry->InMemoryOrderLinks.Flink;
  1124. }
  1125. return TRUE;
  1126. }
  1127. void
  1128. SeiBuildGlobalInclList(
  1129. IN HSDB hSDB // the handle to the database channel
  1130. )
  1131. /*++
  1132. Return: void
  1133. Desc: This function builds the global inclusion list by reading it from the
  1134. database.
  1135. --*/
  1136. {
  1137. TAGREF trDatabase, trLibrary, trInExList, trModule;
  1138. WCHAR wszModule[MAX_PATH];
  1139. CHAR szModule[MAX_PATH];
  1140. ANSI_STRING AnsiString = { 0, sizeof(szModule), szModule };
  1141. UNICODE_STRING UnicodeString;
  1142. PINEXMOD pInExMod;
  1143. SIZE_T len;
  1144. NTSTATUS status;
  1145. //
  1146. // See if the list is not already built.
  1147. //
  1148. if (g_pGlobalInclusionList) {
  1149. return;
  1150. }
  1151. trDatabase = SdbFindFirstTagRef(hSDB, TAGID_ROOT, TAG_DATABASE);
  1152. if (trDatabase == TAGREF_NULL) {
  1153. DPF(dlError, "[SeiBuildGlobalInclList] Corrupt database. TAG_DATABASE\n");
  1154. ASSERT(trDatabase != TAGREF_NULL);
  1155. return;
  1156. }
  1157. trLibrary = SdbFindFirstTagRef(hSDB, trDatabase, TAG_LIBRARY);
  1158. if (trLibrary == TAGREF_NULL) {
  1159. DPF(dlError, "[SeiBuildGlobalInclList] Corrupt database. TAG_LIBRARY\n");
  1160. ASSERT(trLibrary != TAGREF_NULL);
  1161. return;
  1162. }
  1163. trInExList = SdbFindFirstTagRef(hSDB, trLibrary, TAG_INEXCLUDE);
  1164. if (trInExList == TAGREF_NULL) {
  1165. DPF(dlWarning, "[SeiBuildGlobalInclList] no global inclusion list.\n");
  1166. //
  1167. // This is not a problem. It just means there is no
  1168. // global inclusion list.
  1169. //
  1170. return;
  1171. }
  1172. if (trInExList != TAGREF_NULL) {
  1173. DPF(dlInfo, "[SeiBuildGlobalInclList] Global inclusion list:\n");
  1174. }
  1175. while (trInExList != TAGREF_NULL) {
  1176. trModule = SdbFindFirstTagRef(hSDB, trInExList, TAG_MODULE);
  1177. if (trModule == TAGREF_NULL) {
  1178. DPF(dlError,
  1179. "[SeiBuildGlobalInclList] Corrupt database. Global exclusion list w/o module\n");
  1180. ASSERT(trModule != TAGREF_NULL);
  1181. return;
  1182. }
  1183. if (!SdbReadStringTagRef(hSDB, trModule, wszModule, MAX_PATH * sizeof(WCHAR))) {
  1184. DPF(dlError,
  1185. "[SeiBuildGlobalInclList] Corrupt database. Inclusion list w/ bad module\n");
  1186. ASSERT(0);
  1187. return;
  1188. }
  1189. //
  1190. // Check for EXE name. The EXE should not be in the global inclusion list.
  1191. //
  1192. if (wszModule[0] == L'$') {
  1193. //
  1194. // The EXE name should not be specified in the global exclusion list.
  1195. //
  1196. DPF(dlError,
  1197. "[SeiBuildGlobalInclList] EXE name used in the global exclusion list!\n");
  1198. ASSERT(0);
  1199. goto Continue;
  1200. }
  1201. RtlInitUnicodeString(&UnicodeString, wszModule);
  1202. status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  1203. if (!NT_SUCCESS(status)) {
  1204. DPF(dlError,
  1205. "[SeiBuildGlobalInclList] 0x%X Cannot convert UNICODE \"%S\" to ANSI\n",
  1206. status, wszModule);
  1207. ASSERT(0);
  1208. return;
  1209. }
  1210. pInExMod = (PINEXMOD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1211. HEAP_ZERO_MEMORY,
  1212. sizeof(INEXMOD));
  1213. if (pInExMod == NULL) {
  1214. DPF(dlError,
  1215. "[SeiBuildGlobalInclList] Failed to allocate %d bytes\n",
  1216. sizeof(INEXMOD));
  1217. return;
  1218. }
  1219. len = strlen(szModule) + 1;
  1220. pInExMod->pszModule = (char*)(*g_pfnRtlAllocateHeap)(g_pShimHeap, 0, len);
  1221. if (pInExMod->pszModule == NULL) {
  1222. DPF(dlError, "[SeiBuildGlobalInclList] Failed to allocate %d bytes\n", len);
  1223. return;
  1224. }
  1225. RtlCopyMemory(pInExMod->pszModule, szModule, len);
  1226. //
  1227. // Link it in the list.
  1228. //
  1229. pInExMod->pNext = g_pGlobalInclusionList;
  1230. g_pGlobalInclusionList = pInExMod;
  1231. DPF(dlInfo, "\t\"%s\"\n", pInExMod->pszModule);
  1232. Continue:
  1233. trInExList = SdbFindNextTagRef(hSDB, trLibrary, trInExList);
  1234. }
  1235. }
  1236. void
  1237. SeiEmptyInclExclList(
  1238. IN DWORD dwCounter
  1239. )
  1240. /*++
  1241. Return: void
  1242. Desc: This function empties the inclusion and exclusion lists for the specified
  1243. shim.
  1244. --*/
  1245. {
  1246. PINEXMOD pInExMod;
  1247. PINEXMOD pInExFree;
  1248. //
  1249. // First the include list.
  1250. //
  1251. pInExMod = g_pShimInfo[dwCounter].pFirstInclude;
  1252. while (pInExMod != NULL) {
  1253. pInExFree = pInExMod;
  1254. pInExMod = pInExMod->pNext;
  1255. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pInExFree->pszModule);
  1256. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pInExFree);
  1257. }
  1258. g_pShimInfo[dwCounter].pFirstInclude = NULL;
  1259. //
  1260. // Now the exclude list.
  1261. //
  1262. pInExMod = g_pShimInfo[dwCounter].pFirstExclude;
  1263. while (pInExMod != NULL) {
  1264. pInExFree = pInExMod;
  1265. pInExMod = pInExMod->pNext;
  1266. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pInExFree->pszModule);
  1267. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pInExFree);
  1268. }
  1269. g_pShimInfo[dwCounter].pFirstExclude = NULL;
  1270. }
  1271. #define MAX_LOCAL_INCLUDES 64 // max of 64 Incl/Excl statements
  1272. BOOL
  1273. SeiBuildInclExclListForShim(
  1274. IN HSDB hSDB, // handle to the database channel
  1275. IN TAGREF trShim, // TAGREF to the shim entry
  1276. IN DWORD dwCounter, // the index for the shim
  1277. IN LPCWSTR pwszExePath // full path to the EXE
  1278. )
  1279. /*++
  1280. Return: STATUS_SUCCESS on success, STATUS_UNSUCCESSFUL on failure.
  1281. Desc: This function builds the inclusion and exclusion lists for the
  1282. specified shim.
  1283. --*/
  1284. {
  1285. TAGREF trInExList, trModule, trInclude;
  1286. WCHAR wszModule[MAX_PATH];
  1287. CHAR szModule[MAX_PATH];
  1288. ANSI_STRING AnsiString = { 0, sizeof(szModule), szModule };
  1289. UNICODE_STRING UnicodeString;
  1290. PINEXMOD pInExMod;
  1291. SIZE_T len;
  1292. int nInEx;
  1293. BOOL bInclude;
  1294. DWORD trArrInEx[MAX_LOCAL_INCLUDES];
  1295. NTSTATUS status;
  1296. trInExList = SdbFindFirstTagRef(hSDB, trShim, TAG_INEXCLUDE);
  1297. nInEx = 0;
  1298. //
  1299. // Count the number of inclusion/exclusion statements. We need to do
  1300. // this first because the statements are written into the sdb file
  1301. // from bottom to top.
  1302. //
  1303. while (trInExList != TAGREF_NULL && nInEx < MAX_LOCAL_INCLUDES) {
  1304. trArrInEx[nInEx++] = trInExList;
  1305. trInExList = SdbFindNextTagRef(hSDB, trShim, trInExList);
  1306. ASSERT(nInEx <= MAX_LOCAL_INCLUDES);
  1307. }
  1308. if (nInEx == 0) {
  1309. return TRUE;
  1310. }
  1311. nInEx--;
  1312. while (nInEx >= 0) {
  1313. trInExList = trArrInEx[nInEx];
  1314. trInclude = SdbFindFirstTagRef(hSDB, trInExList, TAG_INCLUDE);
  1315. bInclude = (trInclude != TAGREF_NULL);
  1316. trModule = SdbFindFirstTagRef(hSDB, trInExList, TAG_MODULE);
  1317. if (trModule == TAGREF_NULL) {
  1318. DPF(dlError,
  1319. "[SeiBuildInclExclListForShim] Corrupt database. Incl/Excl list w/o module\n");
  1320. ASSERT(trModule != TAGREF_NULL);
  1321. return FALSE;
  1322. }
  1323. if (!SdbReadStringTagRef(hSDB, trModule, wszModule, MAX_PATH * sizeof(WCHAR))) {
  1324. DPF(dlError,
  1325. "[SeiBuildInclExclListForShim] Corrupt database. Incl/Excl list w/ bad module\n");
  1326. ASSERT(0);
  1327. return FALSE;
  1328. }
  1329. //
  1330. // Special case for '*'. '*' means all modules.
  1331. //
  1332. // NOTE: this option is ignored for dynamic shimming.
  1333. //
  1334. if (wszModule[0] == L'*') {
  1335. if (bInclude) {
  1336. //
  1337. // This is INCLUDE MODULE="*"
  1338. // Mark that we are in INCLUDE_ALL mode.
  1339. //
  1340. g_pShimInfo[dwCounter].eInExMode = INCLUDE_ALL;
  1341. } else {
  1342. //
  1343. // This is EXCLUDE MODULE="*"
  1344. // Mark that we are in EXCLUDE_ALL mode.
  1345. //
  1346. g_pShimInfo[dwCounter].eInExMode = EXCLUDE_ALL;
  1347. }
  1348. SeiEmptyInclExclList(dwCounter);
  1349. } else {
  1350. if (wszModule[0] == L'$') {
  1351. //
  1352. // Special case for EXE name. Get the name of the executable.
  1353. //
  1354. LPCWSTR pwszWalk = pwszExePath + wcslen(pwszExePath);
  1355. while (pwszWalk >= pwszExePath) {
  1356. if (*pwszWalk == '\\') {
  1357. break;
  1358. }
  1359. pwszWalk--;
  1360. }
  1361. wcscpy(wszModule, pwszWalk + 1);
  1362. DPF(dlInfo,
  1363. "[SeiBuildInclExclListForShim] EXE name resolved to \"%S\".\n",
  1364. wszModule);
  1365. }
  1366. RtlInitUnicodeString(&UnicodeString, wszModule);
  1367. status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  1368. if (!NT_SUCCESS(status)) {
  1369. DPF(dlError,
  1370. "[SeiBuildInclExclListForShim] 0x%X Cannot convert UNICODE \"%S\" to ANSI\n",
  1371. status, wszModule);
  1372. ASSERT(0);
  1373. return FALSE;
  1374. }
  1375. //
  1376. // Add the module to the correct list.
  1377. //
  1378. pInExMod = (PINEXMOD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1379. HEAP_ZERO_MEMORY,
  1380. sizeof(INEXMOD));
  1381. if (pInExMod == NULL) {
  1382. DPF(dlError,
  1383. "[SeiBuildInclExclListForShim] Failed to allocate %d bytes\n",
  1384. sizeof(INEXMOD));
  1385. return FALSE;
  1386. }
  1387. len = strlen(szModule) + 1;
  1388. pInExMod->pszModule = (char*)(*g_pfnRtlAllocateHeap)(g_pShimHeap, 0, len);
  1389. if (pInExMod->pszModule == NULL) {
  1390. DPF(dlError,
  1391. "[SeiBuildInclExclListForShim] Failed to allocate %d bytes\n", len);
  1392. return FALSE;
  1393. }
  1394. RtlCopyMemory(pInExMod->pszModule, szModule, len);
  1395. //
  1396. // Link it in the list.
  1397. //
  1398. if (bInclude) {
  1399. pInExMod->pNext = g_pShimInfo[dwCounter].pFirstInclude;
  1400. g_pShimInfo[dwCounter].pFirstInclude = pInExMod;
  1401. } else {
  1402. pInExMod->pNext = g_pShimInfo[dwCounter].pFirstExclude;
  1403. g_pShimInfo[dwCounter].pFirstExclude = pInExMod;
  1404. }
  1405. //
  1406. // See if this module is in the other list, and take it out.
  1407. //
  1408. {
  1409. PINEXMOD pInExFree;
  1410. PINEXMOD* ppInExModX;
  1411. if (bInclude) {
  1412. ppInExModX = &g_pShimInfo[dwCounter].pFirstExclude;
  1413. } else {
  1414. ppInExModX = &g_pShimInfo[dwCounter].pFirstInclude;
  1415. }
  1416. while (*ppInExModX != NULL) {
  1417. if (_stricmp((*ppInExModX)->pszModule, szModule) == 0) {
  1418. pInExFree = *ppInExModX;
  1419. *ppInExModX = pInExFree->pNext;
  1420. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pInExFree->pszModule);
  1421. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pInExFree);
  1422. break;
  1423. }
  1424. ppInExModX = &(*ppInExModX)->pNext;
  1425. }
  1426. }
  1427. }
  1428. nInEx--;
  1429. }
  1430. return TRUE;
  1431. }
  1432. BOOL
  1433. SeiCopyGlobalInclList(
  1434. IN DWORD dwCounter
  1435. )
  1436. /*++
  1437. Return: STATUS_SUCCESS on success, STATUS_UNSUCCESSFUL on failure.
  1438. Desc: This function copies the global inclusion list.
  1439. --*/
  1440. {
  1441. PINEXMOD pInExModX;
  1442. SIZE_T len;
  1443. PINEXMOD pInExMod = g_pGlobalInclusionList;
  1444. //
  1445. // Don't do it if we already added it.
  1446. //
  1447. if (g_pShimInfo[dwCounter].pFirstInclude != NULL) {
  1448. return TRUE;
  1449. }
  1450. while (pInExMod != NULL) {
  1451. pInExModX = (PINEXMOD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1452. HEAP_ZERO_MEMORY,
  1453. sizeof(INEXMOD));
  1454. if (pInExModX == NULL) {
  1455. DPF(dlError,
  1456. "[SeiCopyGlobalInclList] (1) Failed to allocate %d bytes\n",
  1457. sizeof(INEXMOD));
  1458. return FALSE;
  1459. }
  1460. len = strlen(pInExMod->pszModule) + 1;
  1461. pInExModX->pszModule = (char*)(*g_pfnRtlAllocateHeap)(g_pShimHeap, 0, len);
  1462. if (pInExModX->pszModule == NULL) {
  1463. DPF(dlError,
  1464. "[SeiCopyGlobalInclList] (2) Failed to allocate %d bytes\n", len);
  1465. return FALSE;
  1466. }
  1467. RtlCopyMemory(pInExModX->pszModule, pInExMod->pszModule, len);
  1468. //
  1469. // Link it in the list.
  1470. //
  1471. pInExModX->pNext = g_pShimInfo[dwCounter].pFirstInclude;
  1472. g_pShimInfo[dwCounter].pFirstInclude = pInExModX;
  1473. pInExMod = pInExMod->pNext;
  1474. }
  1475. return TRUE;
  1476. }
  1477. BOOL
  1478. SeiBuildInclListWithOneModule(
  1479. IN DWORD dwCounter,
  1480. IN LPCSTR lpszModuleToShim
  1481. )
  1482. {
  1483. PINEXMOD pInExMod;
  1484. int len;
  1485. g_pShimInfo[dwCounter].eInExMode = EXCLUDE_ALL;
  1486. //
  1487. // Add the module to the correct list.
  1488. //
  1489. pInExMod = (PINEXMOD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1490. HEAP_ZERO_MEMORY,
  1491. sizeof(INEXMOD));
  1492. if (pInExMod == NULL) {
  1493. DPF(dlError,
  1494. "[SeiBuildInclListWithOneModule] Failed to allocate %d bytes\n",
  1495. sizeof(INEXMOD));
  1496. return FALSE;
  1497. }
  1498. len = strlen(lpszModuleToShim) + 1;
  1499. pInExMod->pszModule = (char*)(*g_pfnRtlAllocateHeap)(g_pShimHeap, 0, len);
  1500. if (pInExMod->pszModule == NULL) {
  1501. DPF(dlError,
  1502. "[SeiBuildInclListWithOneModule] Failed to allocate %d bytes\n", len);
  1503. return FALSE;
  1504. }
  1505. RtlCopyMemory(pInExMod->pszModule, lpszModuleToShim, len);
  1506. //
  1507. // Add it to the list.
  1508. //
  1509. pInExMod->pNext = g_pShimInfo[dwCounter].pFirstInclude;
  1510. g_pShimInfo[dwCounter].pFirstInclude = pInExMod;
  1511. return TRUE;
  1512. }
  1513. BOOL
  1514. SeiBuildInclExclList(
  1515. IN HSDB hSDB, // handle to the database channel
  1516. IN TAGREF trShimRef, // The TAGREF to the shim DLL for which to read the
  1517. // inclusion or exclusion list from the database.
  1518. IN DWORD dwCounter, // Index in the g_pShimInfo array for this shim DLL.
  1519. IN LPCWSTR pwszExePath // The full path name of the main EXE.
  1520. )
  1521. /*++
  1522. Return: STATUS_SUCCESS if successful.
  1523. Desc: This function builds the inclusion or exclusion list for the specified
  1524. shim DLL by reading it from the database.
  1525. --*/
  1526. {
  1527. TAGREF trShim;
  1528. //
  1529. // Set the default mode to EXCLUDE_SYSTEM32
  1530. //
  1531. g_pShimInfo[dwCounter].eInExMode = EXCLUDE_SYSTEM32;
  1532. trShim = SdbGetShimFromShimRef(hSDB, trShimRef);
  1533. if (trShim == TAGREF_NULL) {
  1534. DPF(dlError,
  1535. "[SeiBuildInclExclList] Corrupt database. Couldn't get the DLL from "
  1536. "the LIBRARY section\n");
  1537. return FALSE;
  1538. }
  1539. //
  1540. // Make a copy of the global exclusion list first.
  1541. //
  1542. if (!SeiCopyGlobalInclList(dwCounter)) {
  1543. DPF(dlError,
  1544. "[SeiBuildInclExclList] SeiCopyGlobalInclList failed\n");
  1545. return FALSE;
  1546. }
  1547. //
  1548. // Get DLL specific incl/excl list first.
  1549. //
  1550. if (!SeiBuildInclExclListForShim(hSDB, trShim, dwCounter, pwszExePath)) {
  1551. DPF(dlError,
  1552. "[SeiBuildInclExclList] (1) Corrupt database. Couldn't build incl/excl list\n");
  1553. return FALSE;
  1554. }
  1555. //
  1556. // Now get the incl/excl specified for this shim within its parent EXE tag.
  1557. //
  1558. if (!SeiBuildInclExclListForShim(hSDB, trShimRef, dwCounter, pwszExePath)) {
  1559. DPF(dlError,
  1560. "[SeiBuildInclExclList] (2) Corrupt database. Couldn't build incl/excl list\n");
  1561. return FALSE;
  1562. }
  1563. #if DBG
  1564. //
  1565. // Print the incl/excl list for this shim.
  1566. //
  1567. if (g_pShimInfo[dwCounter].pFirstInclude != NULL) {
  1568. PINEXMOD pInExMod;
  1569. DPF(dlInfo, "[SeiBuildInclExclList] Inclusion list for \"%S\"\n",
  1570. g_pShimInfo[dwCounter].pLdrEntry->BaseDllName.Buffer);
  1571. pInExMod = g_pShimInfo[dwCounter].pFirstInclude;
  1572. while (pInExMod != NULL) {
  1573. DPF(dlInfo, "\t\"%s\"\n", pInExMod->pszModule);
  1574. pInExMod = pInExMod->pNext;
  1575. }
  1576. }
  1577. if (g_pShimInfo[dwCounter].pFirstExclude != NULL) {
  1578. PINEXMOD pInExMod;
  1579. DPF(dlInfo, "[SeiBuildInclExclList] Exclusion list for \"%S\"\n",
  1580. g_pShimInfo[dwCounter].pLdrEntry->BaseDllName.Buffer);
  1581. pInExMod = g_pShimInfo[dwCounter].pFirstExclude;
  1582. while (pInExMod != NULL) {
  1583. DPF(dlInfo, "\t\"%s\"\n", pInExMod->pszModule);
  1584. pInExMod = pInExMod->pNext;
  1585. }
  1586. }
  1587. #endif // DBG
  1588. return TRUE;
  1589. }
  1590. PLDR_DATA_TABLE_ENTRY
  1591. SeiGetLoaderEntry(
  1592. IN PPEB Peb, // The PEB
  1593. IN PVOID pDllBase // The address of the shim DLL to be removed from
  1594. // the loader's lists.
  1595. )
  1596. /*++
  1597. Return: Pointer to the loader entry for the shim DLL being removed.
  1598. Desc: This function removes the shim DLLs from the loader's lists.
  1599. --*/
  1600. {
  1601. PLIST_ENTRY LdrHead;
  1602. PLIST_ENTRY LdrNext;
  1603. PLDR_DATA_TABLE_ENTRY LdrEntry;
  1604. LdrHead = &Peb->Ldr->InMemoryOrderModuleList;
  1605. LdrNext = LdrHead->Flink;
  1606. while (LdrNext != LdrHead) {
  1607. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  1608. if (LdrEntry->DllBase == pDllBase) {
  1609. break;
  1610. }
  1611. LdrNext = LdrEntry->InMemoryOrderLinks.Flink;
  1612. }
  1613. if (LdrNext != LdrHead) {
  1614. return LdrEntry;
  1615. }
  1616. DPF(dlError, "[SeiGetLoaderEntry] Couldn't find shim DLL in the loader list!\n");
  1617. ASSERT(0);
  1618. return NULL;
  1619. }
  1620. void
  1621. SeiLoadPatches(
  1622. IN HSDB hSDB, // handle to the database channel
  1623. IN TAGREF trExe // TAGREF of the EXE for which to get the memory
  1624. // patches from the database
  1625. )
  1626. /*++
  1627. Return: void
  1628. Desc: This function reads the memory patches from the database and
  1629. stores them in the g_pMemoryPatches array.
  1630. --*/
  1631. {
  1632. TAGREF trPatchRef;
  1633. DWORD dwSize;
  1634. //
  1635. // Read the patches for this EXE.
  1636. //
  1637. trPatchRef = SdbFindFirstTagRef(hSDB, trExe, TAG_PATCH_REF);
  1638. while (trPatchRef != TAGREF_NULL) {
  1639. //
  1640. // Get the size of this patch.
  1641. //
  1642. dwSize = 0;
  1643. SdbReadPatchBits(hSDB, trPatchRef, NULL, &dwSize);
  1644. if (dwSize == 0) {
  1645. DPF(dlError, "[SeiLoadPatches] returned 0 for patch size.\n");
  1646. ASSERT(dwSize != 0);
  1647. return;
  1648. }
  1649. if (g_dwMemoryPatchCount == SHIM_MAX_PATCH_COUNT) {
  1650. DPF(dlError, "[SeiLoadPatches] Too many patches.\n");
  1651. return;
  1652. }
  1653. //
  1654. // Allocate memory for the patch bits.
  1655. //
  1656. g_pMemoryPatches[g_dwMemoryPatchCount] = (PBYTE)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1657. HEAP_ZERO_MEMORY,
  1658. dwSize);
  1659. if (g_pMemoryPatches[g_dwMemoryPatchCount] == NULL) {
  1660. DPF(dlError, "[SeiLoadPatches] Failed to allocate %d bytes for patch.\n",
  1661. dwSize);
  1662. return;
  1663. }
  1664. //
  1665. // Read the patch bits from the database.
  1666. //
  1667. if (!SdbReadPatchBits(hSDB,
  1668. trPatchRef,
  1669. g_pMemoryPatches[g_dwMemoryPatchCount],
  1670. &dwSize)) {
  1671. DPF(dlError, "[SeiLoadPatches] Failure getting patch bits.\n");
  1672. ASSERT(0);
  1673. return;
  1674. }
  1675. g_dwMemoryPatchCount++;
  1676. //
  1677. // Get the next patch.
  1678. //
  1679. trPatchRef = SdbFindNextTagRef(hSDB, trExe, trPatchRef);
  1680. }
  1681. }
  1682. BOOL
  1683. SeiGetModuleHandle(
  1684. IN LPSTR pszModule,
  1685. OUT PVOID* pModuleHandle
  1686. )
  1687. /*++
  1688. Return: void
  1689. Desc: This function loops through the loaded modules and gets the
  1690. handle of the specified named module.
  1691. --*/
  1692. {
  1693. ANSI_STRING AnsiString;
  1694. WCHAR wszDllName[128];
  1695. UNICODE_STRING UnicodeString = { 0, sizeof(wszDllName), wszDllName };
  1696. NTSTATUS status;
  1697. RtlInitAnsiString(&AnsiString, pszModule);
  1698. if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UnicodeString,
  1699. &AnsiString,
  1700. FALSE))){
  1701. DPF(dlError,
  1702. "[SeiGetModuleHandle] Failed to convert \"%s\" to UNICODE.\n",
  1703. pszModule);
  1704. return FALSE;
  1705. }
  1706. status = LdrGetDllHandle(NULL,
  1707. NULL,
  1708. &UnicodeString,
  1709. pModuleHandle);
  1710. if (!NT_SUCCESS(status)) {
  1711. DPF(dlError,
  1712. "[SeiGetModuleHandle] Failed to get the handle for \"%s\".\n",
  1713. pszModule);
  1714. return FALSE;
  1715. }
  1716. return TRUE;
  1717. }
  1718. void
  1719. SeiRemoveDll(
  1720. IN LPSTR pszBaseDllName // the named of the unloaded module
  1721. )
  1722. /*++
  1723. Return: void
  1724. Desc: This function loops through the loaded shims info and resets
  1725. the resolved APIs that belong to the specified module that had
  1726. just been unloaded.
  1727. --*/
  1728. {
  1729. DWORD i, j;
  1730. for (i = 0; i < g_dwShimsCount; i++) {
  1731. for (j = 0; j < g_pShimInfo[i].dwHookedAPIs; j++) {
  1732. if (g_pHookArray[i][j].pszModule != NULL &&
  1733. _strcmpi(g_pHookArray[i][j].pszModule, pszBaseDllName) == 0) {
  1734. if ((ULONG_PTR)g_pHookArray[i][j].pszFunctionName < 0x0000FFFF) {
  1735. DPF(dlWarning,
  1736. "[SeiRemoveDll] \"%s!#%d\" not resolved again\n",
  1737. g_pHookArray[i][j].pszModule,
  1738. g_pHookArray[i][j].pszFunctionName);
  1739. } else {
  1740. DPF(dlWarning,
  1741. "[SeiRemoveDll] \"%s!%s\" not resolved again\n",
  1742. g_pHookArray[i][j].pszModule,
  1743. g_pHookArray[i][j].pszFunctionName);
  1744. }
  1745. g_pHookArray[i][j].pfnOld = NULL;
  1746. g_pShimInfo[i].dwFlags &= ~SIF_RESOLVED;
  1747. }
  1748. }
  1749. }
  1750. }
  1751. BOOL
  1752. SeiGetModuleByAddress(
  1753. PVOID pAddress,
  1754. CHAR* pszModuleName,
  1755. BOOL* pbInSystem32
  1756. )
  1757. {
  1758. DWORD i;
  1759. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1760. if ((ULONG_PTR)pAddress >= (ULONG_PTR)g_hHookedModules[i].pDllBase &&
  1761. (ULONG_PTR)pAddress < (ULONG_PTR)g_hHookedModules[i].pDllBase + (ULONG_PTR)g_hHookedModules[i].ulSizeOfImage) {
  1762. //
  1763. // We found the DLL in the hooked list.
  1764. //
  1765. strcpy(pszModuleName, g_hHookedModules[i].szModuleName);
  1766. *pbInSystem32 = g_hHookedModules[i].bInSystem32;
  1767. return TRUE;
  1768. }
  1769. }
  1770. return FALSE;
  1771. }
  1772. PVOID
  1773. StubGetProcAddress(
  1774. IN HMODULE hMod,
  1775. IN LPSTR pszProc
  1776. )
  1777. /*++
  1778. Return: The address of the function specified.
  1779. Desc: Intercepts calls to GetProcAddress to look for hooked functions. If
  1780. a function was hooked, return the top-most stub function.
  1781. --*/
  1782. {
  1783. DWORD i, j;
  1784. DWORD dwDllIndex;
  1785. PHOOKAPI pTopHookAPI = NULL;
  1786. PVOID pfn;
  1787. PFNGETPROCADDRESS pfnOld;
  1788. PVOID retAddress = NULL;
  1789. ULONG ulHash;
  1790. CHAR szBaseDllName[MAX_PATH];
  1791. BOOL bInSystem32;
  1792. pfnOld = g_IntHookAPI[IHA_GetProcAddress].pfnOld;
  1793. pfn = (*pfnOld)(hMod, pszProc);
  1794. if (pfn == NULL) {
  1795. return NULL;
  1796. }
  1797. for (i = 0; i < g_dwShimsCount; i++) {
  1798. for (j = 0; j < g_pShimInfo[i].dwHookedAPIs; j++) {
  1799. if (g_pHookArray[i][j].pfnOld == pfn) {
  1800. pTopHookAPI = SeiConstructChain(pfn, &dwDllIndex);
  1801. if (pTopHookAPI == NULL) {
  1802. DPF(dlError,
  1803. "[StubGetProcAddress] failed to construct the chain for pfn 0x%p\n",
  1804. pfn);
  1805. return pfn;
  1806. }
  1807. //
  1808. // Probably we care about inclusion/exclusion lists here as well.
  1809. //
  1810. RtlCaptureStackBackTrace(1, 1, &retAddress, &ulHash);
  1811. DPF(dlPrint,
  1812. "[StubGetProcAddress] Stack capture caller 0x%p\n",
  1813. retAddress);
  1814. if (retAddress && SeiGetModuleByAddress(retAddress, szBaseDllName, &bInSystem32)) {
  1815. if (SeiIsExcluded(szBaseDllName, pTopHookAPI, bInSystem32)) {
  1816. return pfn;
  1817. }
  1818. }
  1819. if ((ULONG_PTR)pTopHookAPI->pszFunctionName < 0x0000FFFF) {
  1820. DPF(dlInfo,
  1821. "[StubGetProcAddress] called for \"%s!#%d\" 0x%p changed to 0x%p\n",
  1822. pTopHookAPI->pszModule,
  1823. pTopHookAPI->pszFunctionName,
  1824. pfn,
  1825. pTopHookAPI->pfnNew);
  1826. } else {
  1827. DPF(dlInfo,
  1828. "[StubGetProcAddress] called for \"%s!%s\" 0x%p changed to 0x%p\n",
  1829. pTopHookAPI->pszModule,
  1830. pTopHookAPI->pszFunctionName,
  1831. pfn,
  1832. pTopHookAPI->pfnNew);
  1833. }
  1834. return pTopHookAPI->pfnNew;
  1835. }
  1836. }
  1837. }
  1838. return pfn;
  1839. }
  1840. #ifdef SE_WIN2K
  1841. //
  1842. // The Win2k engine needs to hook a few other APIs as well.
  1843. //
  1844. HMODULE
  1845. StubLoadLibraryA(
  1846. IN LPCSTR pszModule
  1847. )
  1848. {
  1849. HMODULE hMod;
  1850. PFNLOADLIBRARYA pfnOld;
  1851. DWORD i;
  1852. pfnOld = g_IntHookAPI[IHA_LoadLibraryA].pfnOld;
  1853. hMod = (*pfnOld)(pszModule);
  1854. if (hMod == NULL) {
  1855. return NULL;
  1856. }
  1857. //
  1858. // Was this DLL already loaded ?
  1859. //
  1860. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1861. if (hMod == g_hHookedModules[i].pDllBase) {
  1862. DPF(dlInfo,
  1863. "[StubLoadLibraryA] DLL \"%s\" was already loaded.\n",
  1864. pszModule);
  1865. return hMod;
  1866. }
  1867. }
  1868. PatchNewModules(FALSE);
  1869. return hMod;
  1870. }
  1871. HMODULE
  1872. StubLoadLibraryW(
  1873. IN LPCWSTR pszModule
  1874. )
  1875. {
  1876. HMODULE hMod;
  1877. PFNLOADLIBRARYW pfnOld;
  1878. DWORD i;
  1879. pfnOld = g_IntHookAPI[IHA_LoadLibraryW].pfnOld;
  1880. hMod = (*pfnOld)(pszModule);
  1881. if (hMod == NULL) {
  1882. return NULL;
  1883. }
  1884. //
  1885. // Was this DLL already loaded ?
  1886. //
  1887. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1888. if (hMod == g_hHookedModules[i].pDllBase) {
  1889. DPF(dlInfo,
  1890. "[StubLoadLibraryW] DLL \"%S\" was already loaded.\n",
  1891. pszModule);
  1892. return hMod;
  1893. }
  1894. }
  1895. PatchNewModules(FALSE);
  1896. return hMod;
  1897. }
  1898. HMODULE
  1899. StubLoadLibraryExA(
  1900. IN LPCSTR pszModule,
  1901. IN HANDLE hFile,
  1902. IN DWORD dwFlags
  1903. )
  1904. {
  1905. HMODULE hMod;
  1906. PFNLOADLIBRARYEXA pfnOld;
  1907. DWORD i;
  1908. pfnOld = g_IntHookAPI[IHA_LoadLibraryExA].pfnOld;
  1909. hMod = (*pfnOld)(pszModule, hFile, dwFlags);
  1910. if (hMod == NULL) {
  1911. return NULL;
  1912. }
  1913. //
  1914. // Was this DLL already loaded ?
  1915. //
  1916. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1917. if (hMod == g_hHookedModules[i].pDllBase) {
  1918. DPF(dlInfo,
  1919. "[StubLoadLibraryExA] DLL \"%s\" was already loaded.\n",
  1920. pszModule);
  1921. return hMod;
  1922. }
  1923. }
  1924. PatchNewModules(FALSE);
  1925. return hMod;
  1926. }
  1927. HMODULE
  1928. StubLoadLibraryExW(
  1929. IN LPCWSTR pszModule,
  1930. IN HANDLE hFile,
  1931. IN DWORD dwFlags
  1932. )
  1933. {
  1934. HMODULE hMod;
  1935. PFNLOADLIBRARYEXW pfnOld;
  1936. DWORD i;
  1937. pfnOld = g_IntHookAPI[IHA_LoadLibraryExW].pfnOld;
  1938. hMod = (*pfnOld)(pszModule, hFile, dwFlags);
  1939. if (hMod == NULL) {
  1940. return NULL;
  1941. }
  1942. //
  1943. // Was this DLL already loaded ?
  1944. //
  1945. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1946. if (hMod == g_hHookedModules[i].pDllBase) {
  1947. DPF(dlInfo,
  1948. "[StubLoadLibraryExW] DLL \"%S\" was already loaded.\n",
  1949. pszModule);
  1950. return hMod;
  1951. }
  1952. }
  1953. PatchNewModules(FALSE);
  1954. return hMod;
  1955. }
  1956. BOOL
  1957. SeiIsDllLoaded(
  1958. IN HMODULE hMod,
  1959. IN PLDR_DATA_TABLE_ENTRY* pLdrEntry
  1960. )
  1961. {
  1962. PPEB Peb = NtCurrentPeb();
  1963. PLIST_ENTRY LdrHead;
  1964. PLIST_ENTRY LdrNext;
  1965. DWORD i;
  1966. //
  1967. // Loop through the loaded modules.
  1968. //
  1969. LdrHead = &Peb->Ldr->InMemoryOrderModuleList;
  1970. LdrNext = LdrHead->Flink;
  1971. while (LdrNext != LdrHead) {
  1972. PLDR_DATA_TABLE_ENTRY LdrEntry;
  1973. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  1974. if (LdrEntry->DllBase == hMod) {
  1975. *pLdrEntry = LdrEntry;
  1976. return TRUE;
  1977. }
  1978. LdrNext = LdrEntry->InMemoryOrderLinks.Flink;
  1979. }
  1980. return FALSE;
  1981. }
  1982. BOOL
  1983. StubFreeLibrary(
  1984. IN HMODULE hLibModule
  1985. )
  1986. {
  1987. DWORD i, j;
  1988. PFNFREELIBRARY pfnOld;
  1989. BOOL bRet;
  1990. PLDR_DATA_TABLE_ENTRY LdrEntry;
  1991. char szBaseDllName[128];
  1992. pfnOld = g_IntHookAPI[IHA_FreeLibrary].pfnOld;
  1993. bRet = (*pfnOld)(hLibModule);
  1994. //
  1995. // See if this DLL is one that we hooked.
  1996. //
  1997. for (i = 0; i < g_dwHookedModuleCount; i++) {
  1998. if (g_hHookedModules[i].pDllBase == hLibModule) {
  1999. break;
  2000. }
  2001. }
  2002. if (i >= g_dwHookedModuleCount) {
  2003. return bRet;
  2004. }
  2005. //
  2006. // Is the DLL still loaded ?
  2007. //
  2008. if (SeiIsDllLoaded(hLibModule, &LdrEntry)) {
  2009. DPF(dlInfo,
  2010. "[StubFreeLibrary] Dll \"%S\" still loaded.\n",
  2011. LdrEntry->BaseDllName.Buffer);
  2012. return bRet;
  2013. }
  2014. strcpy(szBaseDllName, g_hHookedModules[i].szModuleName);
  2015. DPF(dlInfo,
  2016. "[StubFreeLibrary] Removing hooked DLL 0x%p \"%s\"\n",
  2017. hLibModule,
  2018. szBaseDllName);
  2019. //
  2020. // Take it out of the list of hooked modules.
  2021. //
  2022. for (j = i; j < g_dwHookedModuleCount - 1; j++) {
  2023. RtlCopyMemory(g_hHookedModules + j, g_hHookedModules + j + 1, sizeof(HOOKEDMODULE));
  2024. }
  2025. g_hHookedModules[j].pDllBase = NULL;
  2026. strcpy(g_hHookedModules[j].szModuleName, "removed!");
  2027. g_dwHookedModuleCount--;
  2028. //
  2029. // Remove the pfnOld from the HOOKAPIs that were
  2030. // resolved to this DLL
  2031. //
  2032. SeiRemoveDll(szBaseDllName);
  2033. return bRet;
  2034. }
  2035. #endif // SE_WIN2K
  2036. BOOL
  2037. SeiInitFileLog(
  2038. IN LPCWSTR pwszAppName // The full path of the starting EXE
  2039. )
  2040. /*++
  2041. Return: TRUE if the log was initialized.
  2042. Desc: This function checks an environment variable to determine if logging
  2043. is enabled. If so, it will append a header that tells a new app is
  2044. started.
  2045. --*/
  2046. {
  2047. NTSTATUS status;
  2048. UNICODE_STRING EnvName;
  2049. UNICODE_STRING EnvValue;
  2050. UNICODE_STRING FilePath;
  2051. UNICODE_STRING NtSystemRoot;
  2052. WCHAR wszEnvValue[128];
  2053. WCHAR wszLogFile[MAX_PATH];
  2054. HANDLE hfile;
  2055. OBJECT_ATTRIBUTES ObjA;
  2056. LARGE_INTEGER liOffset;
  2057. RTL_RELATIVE_NAME RelativeName;
  2058. ULONG uBytes;
  2059. char szHeader[512];
  2060. char szFormatHeader[] = "-------------------------------------------\r\n"
  2061. " Log \"%S\"\r\n"
  2062. "-------------------------------------------\r\n";
  2063. IO_STATUS_BLOCK ioStatusBlock;
  2064. RtlInitUnicodeString(&EnvName, L"SHIM_FILE_LOG");
  2065. EnvValue.Buffer = wszEnvValue;
  2066. EnvValue.Length = 0;
  2067. EnvValue.MaximumLength = sizeof(wszEnvValue);
  2068. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  2069. if (!NT_SUCCESS(status)) {
  2070. DPF(dlInfo, "[SeiInitFileLog] Logging not enabled\n");
  2071. return FALSE;
  2072. }
  2073. FilePath.Buffer = wszLogFile;
  2074. FilePath.Length = 0;
  2075. FilePath.MaximumLength = sizeof(wszLogFile);
  2076. RtlInitUnicodeString(&NtSystemRoot, USER_SHARED_DATA->NtSystemRoot);
  2077. RtlAppendUnicodeStringToString(&FilePath, &NtSystemRoot);
  2078. RtlAppendUnicodeToString(&FilePath, L"\\AppPatch\\");
  2079. RtlAppendUnicodeStringToString(&FilePath, &EnvValue);
  2080. if (!RtlDosPathNameToNtPathName_U(FilePath.Buffer,
  2081. &FilePath,
  2082. NULL,
  2083. &RelativeName)) {
  2084. DPF(dlError,
  2085. "[SeiInitFileLog] Failed to convert path name \"%S\"\n",
  2086. wszLogFile);
  2087. return FALSE;
  2088. }
  2089. InitializeObjectAttributes(&ObjA,
  2090. &FilePath,
  2091. OBJ_CASE_INSENSITIVE,
  2092. NULL,
  2093. NULL);
  2094. //
  2095. // Open/Create the log file.
  2096. //
  2097. status = NtCreateFile(&hfile,
  2098. FILE_APPEND_DATA | SYNCHRONIZE,
  2099. &ObjA,
  2100. &ioStatusBlock,
  2101. NULL,
  2102. FILE_ATTRIBUTE_NORMAL,
  2103. 0,
  2104. FILE_OPEN_IF,
  2105. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  2106. NULL,
  2107. 0);
  2108. RtlFreeUnicodeString(&FilePath);
  2109. if (!NT_SUCCESS(status)) {
  2110. DPF(dlError,
  2111. "[SeiInitFileLog] 0x%X Cannot open/create log file \"%S\"\n",
  2112. status, wszLogFile);
  2113. return FALSE;
  2114. }
  2115. //
  2116. // Now write a new line in the log file
  2117. //
  2118. ioStatusBlock.Status = 0;
  2119. ioStatusBlock.Information = 0;
  2120. liOffset.LowPart = 0;
  2121. liOffset.HighPart = 0;
  2122. uBytes = (ULONG)sprintf(szHeader, szFormatHeader, pwszAppName);
  2123. status = NtWriteFile(hfile,
  2124. NULL,
  2125. NULL,
  2126. NULL,
  2127. &ioStatusBlock,
  2128. (PVOID)szHeader,
  2129. uBytes,
  2130. &liOffset,
  2131. NULL);
  2132. NtClose(hfile);
  2133. if (!NT_SUCCESS(status)) {
  2134. DPF(dlError,
  2135. "[SeiInitFileLog] 0x%X Cannot write into the log file \"%S\"\n",
  2136. status, wszLogFile);
  2137. return FALSE;
  2138. }
  2139. return TRUE;
  2140. }
  2141. LPWSTR
  2142. SeiGetLayerName(
  2143. IN HSDB hSDB,
  2144. IN TAGREF trLayer
  2145. )
  2146. /*++
  2147. Return: BUGBUG
  2148. Desc: BUGBUG
  2149. --*/
  2150. {
  2151. PDB pdb;
  2152. TAGID tiLayer, tiName;
  2153. LPWSTR pwszName;
  2154. if (!SdbTagRefToTagID(hSDB, trLayer, &pdb, &tiLayer)) {
  2155. DPF(dlError, "[SeiGetLayerName] Failed to get tag id from tag ref\n");
  2156. return NULL;
  2157. }
  2158. tiName = SdbFindFirstTag(pdb, tiLayer, TAG_NAME);
  2159. if (tiName == TAGID_NULL) {
  2160. DPF(dlError,
  2161. "[SeiGetLayerName] Failed to get the name tag id\n");
  2162. return NULL;
  2163. }
  2164. pwszName = SdbGetStringTagPtr(pdb, tiName);
  2165. if (pwszName == NULL) {
  2166. DPF(dlError,
  2167. "[SeiGetLayerName] Cannot read the name of the layer tag\n");
  2168. }
  2169. return pwszName;
  2170. }
  2171. void
  2172. SeiClearLayerEnvVar(
  2173. void
  2174. )
  2175. /*++
  2176. Return: BUGBUG
  2177. Desc: BUGBUG
  2178. --*/
  2179. {
  2180. UNICODE_STRING EnvName;
  2181. NTSTATUS status;
  2182. RtlInitUnicodeString(&EnvName, L"__COMPAT_LAYER");
  2183. status = RtlSetEnvironmentVariable(NULL, &EnvName, NULL);
  2184. if (NT_SUCCESS(status)) {
  2185. DPF(dlInfo, "[SeiClearLayerEnvVar] Cleared env var __COMPAT_LAYER.\n");
  2186. } else {
  2187. DPF(dlError, "[SeiClearLayerEnvVar] Failed to clear __COMPAT_LAYER. 0x%X\n", status);
  2188. }
  2189. }
  2190. BOOL
  2191. SeiIsLayerEnvVarSet(
  2192. void
  2193. )
  2194. /*++
  2195. Return: BUGBUG
  2196. Desc: BUGBUG
  2197. --*/
  2198. {
  2199. NTSTATUS status;
  2200. UNICODE_STRING EnvName;
  2201. UNICODE_STRING EnvValue;
  2202. WCHAR wszEnvValue[128];
  2203. RtlInitUnicodeString(&EnvName, L"__COMPAT_LAYER");
  2204. EnvValue.Buffer = wszEnvValue;
  2205. EnvValue.Length = 0;
  2206. EnvValue.MaximumLength = sizeof(wszEnvValue);
  2207. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  2208. return NT_SUCCESS(status);
  2209. }
  2210. BOOL
  2211. SeiCheckLayerEnvVarFlags(
  2212. BOOL* pbApplyExes,
  2213. BOOL* pbApplyToSystemExes
  2214. )
  2215. /*++
  2216. Return: BUGBUG
  2217. Desc: BUGBUG
  2218. --*/
  2219. {
  2220. NTSTATUS status;
  2221. UNICODE_STRING EnvName;
  2222. UNICODE_STRING EnvValue;
  2223. WCHAR wszEnvValue[128] = L"";
  2224. LPWSTR pwszEnvTemp;
  2225. if (pbApplyExes) {
  2226. *pbApplyExes = TRUE;
  2227. }
  2228. if (pbApplyToSystemExes) {
  2229. *pbApplyToSystemExes = FALSE;
  2230. }
  2231. RtlInitUnicodeString(&EnvName, L"__COMPAT_LAYER");
  2232. EnvValue.Buffer = wszEnvValue;
  2233. EnvValue.Length = 0;
  2234. EnvValue.MaximumLength = sizeof(wszEnvValue);
  2235. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  2236. //
  2237. // Skip over and handle special flag characters
  2238. // '!' means don't use any EXE entries from the DB
  2239. // '#' means go ahead and apply layers to system EXEs
  2240. //
  2241. if (NT_SUCCESS(status)) {
  2242. pwszEnvTemp = EnvValue.Buffer;
  2243. while (*pwszEnvTemp) {
  2244. if (*pwszEnvTemp == L'!') {
  2245. if (pbApplyExes) {
  2246. *pbApplyExes = FALSE;
  2247. }
  2248. } else if (*pwszEnvTemp == L'#') {
  2249. if (pbApplyToSystemExes) {
  2250. *pbApplyToSystemExes = TRUE;
  2251. }
  2252. } else {
  2253. break;
  2254. }
  2255. pwszEnvTemp++;
  2256. }
  2257. }
  2258. return NT_SUCCESS(status);
  2259. }
  2260. void
  2261. SeiSetLayerEnvVar(
  2262. WCHAR* pwszName
  2263. )
  2264. /*++
  2265. Return: BUGBUG
  2266. Desc: BUGBUG
  2267. --*/
  2268. {
  2269. NTSTATUS status;
  2270. UNICODE_STRING EnvName;
  2271. UNICODE_STRING EnvValue;
  2272. WCHAR wszEnvValue[128];
  2273. RtlInitUnicodeString(&EnvName, L"__COMPAT_LAYER");
  2274. EnvValue.Buffer = wszEnvValue;
  2275. EnvValue.Length = 0;
  2276. EnvValue.MaximumLength = sizeof(wszEnvValue);
  2277. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  2278. if (NT_SUCCESS(status) && (EnvValue.Buffer[0] == L'!' || EnvValue.Buffer[1] == L'!')) {
  2279. //
  2280. // There should be no way to add extra layers to the list,
  2281. // So we should leave it alone.
  2282. //
  2283. return;
  2284. }
  2285. //
  2286. // We need to set the environment variable.
  2287. //
  2288. if (pwszName != NULL) {
  2289. RtlInitUnicodeString(&EnvValue, pwszName);
  2290. status = RtlSetEnvironmentVariable(NULL, &EnvName, &EnvValue);
  2291. if (NT_SUCCESS(status)) {
  2292. DPF(dlInfo, "[SeiSetLayerEnvVar] Env var set __COMPAT_LAYER=\"%S\"\n", pwszName);
  2293. } else {
  2294. DPF(dlError, "[SeiSetLayerEnvVar] Failed to set __COMPAT_LAYER. 0x%X\n", status);
  2295. }
  2296. }
  2297. }
  2298. BOOL
  2299. SeiAddInternalHooks(
  2300. DWORD dwCounter
  2301. )
  2302. /*++
  2303. Return: FALSE if the internal hooks have been already added, TRUE otherwise
  2304. Desc: BUGBUG
  2305. --*/
  2306. {
  2307. if (g_bInternalHooksUsed) {
  2308. return FALSE;
  2309. }
  2310. g_bInternalHooksUsed = TRUE;
  2311. ZeroMemory(g_IntHookAPI, sizeof(HOOKAPI) * IHA_COUNT);
  2312. ZeroMemory(g_IntHookEx, sizeof(HOOKAPIEX) * IHA_COUNT);
  2313. g_IntHookAPI[IHA_GetProcAddress].pszModule = "kernel32.dll";
  2314. g_IntHookAPI[IHA_GetProcAddress].pszFunctionName = "GetProcAddress";
  2315. g_IntHookAPI[IHA_GetProcAddress].pfnNew = (PVOID)StubGetProcAddress;
  2316. g_IntHookAPI[IHA_GetProcAddress].pHookEx = &g_IntHookEx[IHA_GetProcAddress];
  2317. g_IntHookAPI[IHA_GetProcAddress].pHookEx->dwShimID = dwCounter;
  2318. #ifdef SE_WIN2K
  2319. g_IntHookAPI[IHA_LoadLibraryA].pszModule = "kernel32.dll";
  2320. g_IntHookAPI[IHA_LoadLibraryA].pszFunctionName = "LoadLibraryA";
  2321. g_IntHookAPI[IHA_LoadLibraryA].pfnNew = (PVOID)StubLoadLibraryA;
  2322. g_IntHookAPI[IHA_LoadLibraryA].pHookEx = &g_IntHookEx[IHA_LoadLibraryA];
  2323. g_IntHookAPI[IHA_LoadLibraryA].pHookEx->dwShimID = dwCounter;
  2324. g_IntHookAPI[IHA_LoadLibraryW].pszModule = "kernel32.dll";
  2325. g_IntHookAPI[IHA_LoadLibraryW].pszFunctionName = "LoadLibraryW";
  2326. g_IntHookAPI[IHA_LoadLibraryW].pfnNew = (PVOID)StubLoadLibraryW;
  2327. g_IntHookAPI[IHA_LoadLibraryW].pHookEx = &g_IntHookEx[IHA_LoadLibraryW];
  2328. g_IntHookAPI[IHA_LoadLibraryW].pHookEx->dwShimID = dwCounter;
  2329. g_IntHookAPI[IHA_LoadLibraryExA].pszModule = "kernel32.dll";
  2330. g_IntHookAPI[IHA_LoadLibraryExA].pszFunctionName = "LoadLibraryExA";
  2331. g_IntHookAPI[IHA_LoadLibraryExA].pfnNew = (PVOID)StubLoadLibraryExA;
  2332. g_IntHookAPI[IHA_LoadLibraryExA].pHookEx = &g_IntHookEx[IHA_LoadLibraryExA];
  2333. g_IntHookAPI[IHA_LoadLibraryExA].pHookEx->dwShimID = dwCounter;
  2334. g_IntHookAPI[IHA_LoadLibraryExW].pszModule = "kernel32.dll";
  2335. g_IntHookAPI[IHA_LoadLibraryExW].pszFunctionName = "LoadLibraryExW";
  2336. g_IntHookAPI[IHA_LoadLibraryExW].pfnNew = (PVOID)StubLoadLibraryExW;
  2337. g_IntHookAPI[IHA_LoadLibraryExW].pHookEx = &g_IntHookEx[IHA_LoadLibraryExW];
  2338. g_IntHookAPI[IHA_LoadLibraryExW].pHookEx->dwShimID = dwCounter;
  2339. g_IntHookAPI[IHA_FreeLibrary].pszModule = "kernel32.dll";
  2340. g_IntHookAPI[IHA_FreeLibrary].pszFunctionName = "FreeLibrary";
  2341. g_IntHookAPI[IHA_FreeLibrary].pfnNew = (PVOID)StubFreeLibrary;
  2342. g_IntHookAPI[IHA_FreeLibrary].pHookEx = &g_IntHookEx[IHA_FreeLibrary];
  2343. g_IntHookAPI[IHA_FreeLibrary].pHookEx->dwShimID = dwCounter;
  2344. #endif // SE_WIN2K
  2345. //
  2346. // Add the info for our internal hook
  2347. //
  2348. g_pShimInfo[dwCounter].dwHookedAPIs = IHA_COUNT;
  2349. g_pShimInfo[dwCounter].pDllBase = g_pShimEngModHandle;
  2350. g_pShimInfo[dwCounter].pLdrEntry = g_pShimEngLdrEntry;
  2351. g_pShimInfo[dwCounter].eInExMode = INCLUDE_ALL;
  2352. wcscpy(g_pShimInfo[dwCounter].wszName, L"SHIMENG.DLL");
  2353. g_pHookArray[dwCounter] = g_IntHookAPI;
  2354. return TRUE;
  2355. }
  2356. void
  2357. NotifyShims(
  2358. int nReason,
  2359. UINT_PTR extraInfo
  2360. )
  2361. {
  2362. DWORD i, j;
  2363. NTSTATUS status;
  2364. ANSI_STRING ProcedureNameString;
  2365. PFNNOTIFYSHIMS pfnNotifyShims = NULL;
  2366. for (i = 0; i < g_dwShimsCount; i++) {
  2367. for (j = 0; j < i; j++) {
  2368. if (g_pShimInfo[i].pDllBase == g_pShimInfo[j].pDllBase) {
  2369. break;
  2370. }
  2371. }
  2372. if (i == j && g_pShimInfo[i].pLdrEntry != g_pShimEngLdrEntry) {
  2373. //
  2374. // Get the NotifyShims entry point
  2375. //
  2376. RtlInitString(&ProcedureNameString, "NotifyShims");
  2377. status = LdrGetProcedureAddress(g_pShimInfo[i].pDllBase,
  2378. &ProcedureNameString,
  2379. 0,
  2380. (PVOID*)&pfnNotifyShims);
  2381. if (!NT_SUCCESS(status) || pfnNotifyShims == NULL) {
  2382. DPF(dlError,
  2383. "[NotifyShims] Failed to get 'NotifyShims' address, DLL \"%S\"\n",
  2384. g_pShimInfo[i].wszName);
  2385. } else {
  2386. //
  2387. // Call the notification function.
  2388. //
  2389. (*pfnNotifyShims)(nReason, extraInfo);
  2390. }
  2391. }
  2392. }
  2393. return;
  2394. }
  2395. void
  2396. NotifyShimDlls(
  2397. void
  2398. )
  2399. /*++
  2400. Return: void
  2401. Desc: Notify the shim DLLs that all the static linked modules have run
  2402. their init routines.
  2403. --*/
  2404. {
  2405. NotifyShims(SN_STATIC_DLLS_INITIALIZED, 0);
  2406. #ifdef SE_WIN2K
  2407. //
  2408. // On Win2k we need to restore the code at the entry point.
  2409. //
  2410. RestoreOriginalCode();
  2411. #endif // SE_WIN2K
  2412. return;
  2413. }
  2414. BOOL
  2415. SeiGetExeName(
  2416. PPEB Peb,
  2417. LPWSTR pwszExeName
  2418. )
  2419. /*++
  2420. Return: BUGBUG
  2421. Desc: BUGBUG
  2422. --*/
  2423. {
  2424. PLDR_DATA_TABLE_ENTRY Entry;
  2425. PLIST_ENTRY Head;
  2426. Head = &Peb->Ldr->InLoadOrderModuleList;
  2427. Head = Head->Flink;
  2428. Entry = CONTAINING_RECORD(Head, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  2429. wcscpy(pwszExeName, Entry->FullDllName.Buffer);
  2430. //
  2431. // Save the exe name in our global
  2432. //
  2433. wcscpy(g_szExeName, Entry->BaseDllName.Buffer);
  2434. #ifdef SE_WIN2K
  2435. InjectNotificationCode(Entry->EntryPoint);
  2436. #endif // SE_WIN2K
  2437. return TRUE;
  2438. }
  2439. #ifndef SE_WIN2K
  2440. int
  2441. SE_IsShimDll(
  2442. IN PVOID pDllBase // The address of a loaded DLL
  2443. )
  2444. /*++
  2445. Return: TRUE if the DLL is one of our shim DLLs
  2446. Desc: This function checks to see if a DLL is one of the shim DLLs
  2447. loaded in this process.
  2448. --*/
  2449. {
  2450. DWORD i;
  2451. for (i = 0; i < g_dwShimsCount; i++) {
  2452. if (g_pShimInfo[i].pDllBase == pDllBase) {
  2453. return 1;
  2454. }
  2455. }
  2456. //
  2457. // Special hack for the apphelp case
  2458. //
  2459. if (pDllBase == g_hApphelpDllHelper) {
  2460. return 1;
  2461. }
  2462. return 0;
  2463. }
  2464. void
  2465. SeiSetEntryProcessed(
  2466. IN PPEB Peb
  2467. )
  2468. /*++
  2469. Return: void
  2470. Desc: This function hacks the loader list of loaded DLLs and marks them
  2471. to tell the loader that they executed their init routines even if
  2472. that is not the case. This needs to be done so that our shim mechanism
  2473. is effective before the staticly loaded module get to execute their
  2474. init routines.
  2475. --*/
  2476. {
  2477. PLIST_ENTRY LdrHead;
  2478. PLIST_ENTRY LdrNext;
  2479. PLDR_DATA_TABLE_ENTRY LdrEntry;
  2480. if (g_bComPlusImage) {
  2481. //
  2482. // COM+ images mess with the loader in ntdll. Don't step on ntdll's
  2483. // toes by messing with LDRP_ENTRY_PROCESSED.
  2484. //
  2485. return;
  2486. }
  2487. //
  2488. // Loop through the loaded modules and set LDRP_ENTRY_PROCESSED as
  2489. // needed. Don't do this for ntdll.dll and kernel32.dll.
  2490. // This needs to be done so when we load the shim DLLs the routines for
  2491. // the statically linked libraries don't get called.
  2492. //
  2493. LdrHead = &Peb->Ldr->InInitializationOrderModuleList;
  2494. LdrNext = LdrHead->Flink;
  2495. while (LdrNext != LdrHead) {
  2496. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
  2497. if (RtlCompareUnicodeString(&Kernel32String, &LdrEntry->BaseDllName, TRUE) != 0 &&
  2498. RtlCompareUnicodeString(&VerifierdllString, &LdrEntry->BaseDllName, TRUE) != 0 &&
  2499. RtlCompareUnicodeString(&NtdllString, &LdrEntry->BaseDllName, TRUE) != 0 &&
  2500. !SE_IsShimDll(LdrEntry->DllBase) &&
  2501. _wcsicmp(LdrEntry->BaseDllName.Buffer, g_wszShimDllInLoading) != 0) {
  2502. LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
  2503. DPF(dlWarning,
  2504. "[SeiSetEntryProcessed] Touching 0x%X \"%S\"\n",
  2505. LdrEntry->DllBase,
  2506. LdrEntry->BaseDllName.Buffer);
  2507. } else {
  2508. DPF(dlWarning,
  2509. "[SeiSetEntryProcessed] Don't mess with 0x%X \"%S\"\n",
  2510. LdrEntry->DllBase,
  2511. LdrEntry->BaseDllName.Buffer);
  2512. }
  2513. LdrNext = LdrEntry->InInitializationOrderLinks.Flink;
  2514. }
  2515. #if DBG
  2516. DPF(dlInfo, "[SeiSetEntryProcessed] In memory:\n");
  2517. LdrHead = &Peb->Ldr->InMemoryOrderModuleList;
  2518. LdrNext = LdrHead->Flink;
  2519. while (LdrNext != LdrHead) {
  2520. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  2521. DPF(dlInfo,
  2522. "\t0x%X \"%S\"\n",
  2523. LdrEntry->DllBase,
  2524. LdrEntry->BaseDllName.Buffer);
  2525. LdrNext = LdrEntry->InMemoryOrderLinks.Flink;
  2526. }
  2527. DPF(dlInfo, "\n[SeiSetEntryProcessed] In load:\n");
  2528. LdrHead = &Peb->Ldr->InLoadOrderModuleList;
  2529. LdrNext = LdrHead->Flink;
  2530. while (LdrNext != LdrHead) {
  2531. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  2532. DPF(dlInfo,
  2533. "\t0x%X \"%S\"\n",
  2534. LdrEntry->DllBase,
  2535. LdrEntry->BaseDllName.Buffer);
  2536. LdrNext = LdrEntry->InLoadOrderLinks.Flink;
  2537. }
  2538. #endif // DBG
  2539. }
  2540. void
  2541. SeiResetEntryProcessed(
  2542. PPEB Peb
  2543. )
  2544. /*++
  2545. Return: void
  2546. Desc: This function restores the flag in the loader's list
  2547. of loaded DLLs that tells they need to run their init
  2548. routines (see LdrpSetEntryProcessed)
  2549. --*/
  2550. {
  2551. PLIST_ENTRY LdrHead;
  2552. PLIST_ENTRY LdrNext;
  2553. if (g_bComPlusImage) {
  2554. //
  2555. // COM+ images mess with the loader in ntdll. Don't step on ntdll's
  2556. // toes by messing with LDRP_ENTRY_PROCESSED.
  2557. //
  2558. return;
  2559. }
  2560. //
  2561. // Loop through the loaded modules and remove LDRP_ENTRY_PROCESSED as
  2562. // needed. Don't do this for ntdll.dll, kernel32.dll and all the shim DLLs
  2563. //
  2564. LdrHead = &Peb->Ldr->InInitializationOrderModuleList;
  2565. LdrNext = LdrHead->Flink;
  2566. while (LdrNext != LdrHead) {
  2567. PLDR_DATA_TABLE_ENTRY LdrEntry;
  2568. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
  2569. if (RtlCompareUnicodeString(&Kernel32String, &LdrEntry->BaseDllName, TRUE) != 0 &&
  2570. RtlCompareUnicodeString(&VerifierdllString, &LdrEntry->BaseDllName, TRUE) != 0 &&
  2571. RtlCompareUnicodeString(&NtdllString, &LdrEntry->BaseDllName, TRUE) != 0 &&
  2572. LdrEntry->DllBase != g_pShimEngModHandle &&
  2573. !SE_IsShimDll(LdrEntry->DllBase)) {
  2574. LdrEntry->Flags &= ~LDRP_ENTRY_PROCESSED;
  2575. DPF(dlWarning,
  2576. "[SeiResetEntryProcessed] Reseting \"%S\"\n",
  2577. LdrEntry->BaseDllName.Buffer);
  2578. } else {
  2579. DPF(dlWarning,
  2580. "[SeiResetEntryProcessed] Don't mess with \"%S\"\n",
  2581. LdrEntry->BaseDllName.Buffer);
  2582. }
  2583. LdrNext = LdrEntry->InInitializationOrderLinks.Flink;
  2584. }
  2585. }
  2586. void
  2587. SE_GetProcAddress(
  2588. PVOID* pProcedureAddress // Pointer containing the return from the original
  2589. // LdrGetProcedureAddress. This functions fils this
  2590. // pointer with the eventual replacement from the
  2591. // HOOKAPI arrays
  2592. )
  2593. /*++
  2594. Return: void
  2595. Desc: Scans HOOKAPI arrays for pfnOld and return pfnNew if this is
  2596. a shimmed API
  2597. --*/
  2598. {
  2599. return;
  2600. UNREFERENCED_PARAMETER(pProcedureAddress);
  2601. }
  2602. void
  2603. SE_DllLoaded(
  2604. PLDR_DATA_TABLE_ENTRY LdrEntry
  2605. )
  2606. {
  2607. if (g_bShimInitialized) {
  2608. #if DBG
  2609. DWORD i;
  2610. //
  2611. // Was this DLL already loaded ?
  2612. //
  2613. for (i = 0; i < g_dwHookedModuleCount; i++) {
  2614. if (LdrEntry->DllBase == g_hHookedModules[i].pDllBase) {
  2615. DPF(dlError,
  2616. "[SE_DllLoaded] DLL \"%s\" was already loaded.\n",
  2617. g_hHookedModules[i].szModuleName);
  2618. }
  2619. }
  2620. #endif // DBG
  2621. DPF(dlInfo,
  2622. "[SE_DllLoaded] AFTER INIT. loading DLL \"%S\".\n",
  2623. LdrEntry->BaseDllName.Buffer);
  2624. PatchNewModules(FALSE);
  2625. } else if (g_bShimDuringInit) {
  2626. DPF(dlInfo,
  2627. "[SE_DllLoaded] INIT. loading DLL \"%S\".\n",
  2628. LdrEntry->BaseDllName.Buffer);
  2629. SeiSetEntryProcessed(NtCurrentPeb());
  2630. }
  2631. return;
  2632. UNREFERENCED_PARAMETER(LdrEntry);
  2633. }
  2634. void
  2635. SE_DllUnloaded(
  2636. PLDR_DATA_TABLE_ENTRY Entry // The pointer to the loader entry for the DLL that is
  2637. // being unloaded.
  2638. )
  2639. /*++
  2640. Return: void
  2641. Desc: This notification comes from LdrUnloadDll. This function looks up
  2642. to see if we have HOOKAPI that have their original functions in
  2643. this DLL. If that is the case then HOOKAPI.pfnOld is set back to
  2644. NULL.
  2645. --*/
  2646. {
  2647. DWORD i, j;
  2648. CHAR szBaseDllName[128];
  2649. ANSI_STRING AnsiString = { 0, sizeof(szBaseDllName), szBaseDllName };
  2650. if (g_dwShimsCount == 0) {
  2651. return;
  2652. }
  2653. //
  2654. // See if this DLL is one that we hooked.
  2655. //
  2656. for (i = 0; i < g_dwHookedModuleCount; i++) {
  2657. if (g_hHookedModules[i].pDllBase == Entry->DllBase) {
  2658. break;
  2659. }
  2660. }
  2661. if (i >= g_dwHookedModuleCount) {
  2662. return;
  2663. }
  2664. DPF(dlWarning,
  2665. "[SEi_DllUnloaded] Removing hooked DLL 0x%p \"%S\"\n",
  2666. Entry->DllBase,
  2667. Entry->BaseDllName.Buffer);
  2668. //
  2669. // Take it out of the list of hooked modules.
  2670. //
  2671. for (j = i; j < g_dwHookedModuleCount - 1; j++) {
  2672. RtlCopyMemory(g_hHookedModules + j, g_hHookedModules + j + 1, sizeof(HOOKEDMODULE));
  2673. }
  2674. g_hHookedModules[j].pDllBase = NULL;
  2675. strcpy(g_hHookedModules[j].szModuleName, "removed!");
  2676. g_dwHookedModuleCount--;
  2677. //
  2678. // Remove the pfnOld from the HOOKAPIs that were
  2679. // resolved to this DLL.
  2680. //
  2681. if (!NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString, &Entry->BaseDllName, FALSE))) {
  2682. DPF(dlError,
  2683. "[SEi_DllUnloaded] Cannot convert \"%S\" to ANSI\n",
  2684. Entry->BaseDllName.Buffer);
  2685. return;
  2686. }
  2687. SeiRemoveDll(szBaseDllName);
  2688. }
  2689. BOOLEAN
  2690. SE_InstallAfterInit(
  2691. IN PUNICODE_STRING UnicodeImageName, // The name of the starting EXE
  2692. IN PVOID pShimExeData // The pointer provided by apphelp.dll
  2693. )
  2694. /*++
  2695. Return: FALSE if the shim engine should be unloaded, TRUE otherwise
  2696. Desc: Calls the notification function for static linked modules.
  2697. --*/
  2698. {
  2699. NotifyShimDlls();
  2700. if (g_dwShimsCount == 0 && g_dwMemoryPatchCount == 0) {
  2701. return FALSE;
  2702. }
  2703. return TRUE;
  2704. UNREFERENCED_PARAMETER(UnicodeImageName);
  2705. UNREFERENCED_PARAMETER(pShimExeData);
  2706. }
  2707. #endif // SE_WIN2K
  2708. LPWSTR
  2709. SeiGetShortName(
  2710. IN LPCWSTR pwszDLLPath
  2711. )
  2712. /*++
  2713. Return: The pointer to the short name from the full path
  2714. Desc: Gets the pointer to the short name from the full path.
  2715. --*/
  2716. {
  2717. LPWSTR pwsz;
  2718. pwsz = (LPWSTR)pwszDLLPath + wcslen(pwszDLLPath);
  2719. while (pwsz >= pwszDLLPath) {
  2720. if (*pwsz == L'\\') {
  2721. break;
  2722. }
  2723. pwsz--;
  2724. }
  2725. return pwsz + 1;
  2726. }
  2727. BOOL
  2728. SeiInitGlobals(
  2729. IN LPCWSTR lpszFullPath
  2730. )
  2731. {
  2732. PPEB Peb = NtCurrentPeb();
  2733. BOOL bResult;
  2734. BOOL bWow64 = FALSE;
  2735. if (g_bInitGlobals) {
  2736. return TRUE;
  2737. }
  2738. //
  2739. // Nab the system32 and windows directory path and length.
  2740. //
  2741. wcscpy(g_szSystem32, USER_SHARED_DATA->NtSystemRoot);
  2742. IsWow64Process(GetCurrentProcess(), &bWow64);
  2743. if (bWow64) {
  2744. wcscat(g_szSystem32, L"\\SysWow64\\");
  2745. } else {
  2746. wcscat(g_szSystem32, L"\\System32\\");
  2747. }
  2748. g_dwSystem32StrLen = wcslen(g_szSystem32);
  2749. wcscpy(g_szSxS, USER_SHARED_DATA->NtSystemRoot);
  2750. wcscat(g_szSxS, L"\\WinSxS\\");
  2751. g_dwSxSStrLen = wcslen(g_szSxS);
  2752. wcscpy(g_szWindir, USER_SHARED_DATA->NtSystemRoot);
  2753. wcscat(g_szWindir, L"\\");
  2754. g_dwWindirStrLen = wcslen(g_szWindir);
  2755. wcscpy(g_szCmdExePath, g_szSystem32);
  2756. wcscat(g_szCmdExePath, L"cmd.exe");
  2757. //
  2758. // Initialize our global function pointers.
  2759. //
  2760. // This is done because these functions may be hooked by a shim and
  2761. // we don't want to trip over a shim hook internally. If one of these
  2762. // functions is hooked, these global pointers will be overwritten
  2763. // with thunk addresses.
  2764. //
  2765. g_pfnRtlAllocateHeap = RtlAllocateHeap;
  2766. g_pfnRtlFreeHeap = RtlFreeHeap;
  2767. //
  2768. // Set up our own shim heap.
  2769. //
  2770. g_pShimHeap = RtlCreateHeap(HEAP_GROWABLE,
  2771. 0, // location isn't important
  2772. 64 * 1024, // 64k is the initial heap size
  2773. 8 * 1024, // bring in an 1/8 of the reserved pages
  2774. 0,
  2775. 0);
  2776. if (g_pShimHeap == NULL) {
  2777. //
  2778. // We didn't get our heap.
  2779. //
  2780. DPF(dlError, "[SeiInitGlobals] Can't create shim heap.\n");
  2781. return FALSE;
  2782. }
  2783. //
  2784. // Get the DLL handle for this shim engine
  2785. //
  2786. #ifdef SE_WIN2K
  2787. bResult = SeiGetModuleHandle("Shim.dll", &g_pShimEngModHandle);
  2788. #else
  2789. bResult = SeiGetModuleHandle("ShimEng.dll", &g_pShimEngModHandle);
  2790. #endif // SE_WIN2K
  2791. if (!bResult) {
  2792. DPF(dlError, "[SeiInitGlobals] Failed to get the shim engine's handle\n");
  2793. return FALSE;
  2794. }
  2795. g_pShimEngLdrEntry = SeiGetLoaderEntry(Peb, g_pShimEngModHandle);
  2796. //
  2797. // Setup the log file.
  2798. //
  2799. SeiInitFileLog(lpszFullPath);
  2800. g_bInitGlobals = TRUE;
  2801. return TRUE;
  2802. }
  2803. void
  2804. SeiLayersCheck(
  2805. IN LPCWSTR lpszFullPath,
  2806. OUT LPBOOL lpbApplyExes,
  2807. OUT LPBOOL lpbApplyToSystemExes,
  2808. OUT SDBQUERYRESULT* psdbQuery
  2809. )
  2810. {
  2811. BOOL bLayerEnvSet = FALSE;
  2812. BOOL bCmdExe = FALSE;
  2813. //
  2814. // Get the flags from the environment variable, if any.
  2815. //
  2816. bLayerEnvSet = SeiCheckLayerEnvVarFlags(lpbApplyExes, lpbApplyToSystemExes);
  2817. //
  2818. // make sure we are not cmd.exe
  2819. //
  2820. bCmdExe = (_wcsicmp(lpszFullPath, g_szCmdExePath) == 0);
  2821. //
  2822. // Unless the environment variable has the flag that allows layer shimming of
  2823. // system exes, check for the EXE being in System32 or Windir.
  2824. // If it is, disable any layer that is coming from the environment variable,
  2825. // and clear the environment variable so the layer won't be propagated.
  2826. //
  2827. if (bLayerEnvSet && !*lpbApplyToSystemExes) {
  2828. if (g_dwSystem32StrLen &&
  2829. _wcsnicmp(g_szSystem32, lpszFullPath, g_dwSystem32StrLen) == 0) {
  2830. //
  2831. // In this case, we'll exclude anything in System32 or any
  2832. // subdirectories.
  2833. //
  2834. DPF(dlWarning,
  2835. "[SeiLayersCheck] Won't apply layer to \"%S\" because it is in System32.\n",
  2836. lpszFullPath);
  2837. psdbQuery->atrLayers[0] = TAGREF_NULL;
  2838. if (!bCmdExe) {
  2839. SeiClearLayerEnvVar();
  2840. }
  2841. } else if (!*lpbApplyToSystemExes &&
  2842. g_dwWindirStrLen &&
  2843. _wcsnicmp(g_szWindir, lpszFullPath, g_dwWindirStrLen) == 0) {
  2844. DWORD i;
  2845. BOOL bInWindir = TRUE;
  2846. //
  2847. // The app is somewhere in the windows tree, but we only want to exclude
  2848. // the windows directory, not the subdirectories.
  2849. //
  2850. for (i = g_dwWindirStrLen; lpszFullPath[i] != 0; ++i) {
  2851. if (lpszFullPath[i] == L'\\') {
  2852. //
  2853. // It's in a subdirectory.
  2854. //
  2855. bInWindir = FALSE;
  2856. break;
  2857. }
  2858. }
  2859. if (bInWindir) {
  2860. DPF(dlWarning,
  2861. "[SeiLayersCheck] Won't apply layer(s) to \"%S\" because"
  2862. " it is in Windows dir.\n",
  2863. lpszFullPath);
  2864. psdbQuery->atrLayers[0] = TAGREF_NULL;
  2865. if (!bCmdExe) {
  2866. SeiClearLayerEnvVar();
  2867. }
  2868. }
  2869. }
  2870. }
  2871. }
  2872. void
  2873. SeiPropagateLayers(
  2874. IN HSDB hSDB,
  2875. IN SDBQUERYRESULT* psdbQuery,
  2876. IN BOOL bApplyExes,
  2877. IN BOOL bApplyToSystemExes,
  2878. OUT LPDWORD lpdwShimsCount
  2879. )
  2880. {
  2881. int i;
  2882. WCHAR szFullEnvVar[MAX_PATH];
  2883. TAGREF trShimRef;
  2884. //
  2885. // Count the DLLs that trLayer uses, and put together the environment variable
  2886. //
  2887. szFullEnvVar[0] = 0;
  2888. //
  2889. // Make sure to propagate the flags.
  2890. //
  2891. if (!bApplyExes) {
  2892. wcscat(szFullEnvVar, L"!");
  2893. }
  2894. if (bApplyToSystemExes) {
  2895. wcscat(szFullEnvVar, L"#");
  2896. }
  2897. for (i = 0; i < SDB_MAX_LAYERS && psdbQuery->atrLayers[i] != TAGREF_NULL; ++i) {
  2898. WCHAR* pszEnvVar;
  2899. //
  2900. // Get the environment var and tack it onto the full string
  2901. //
  2902. pszEnvVar = SeiGetLayerName(hSDB, psdbQuery->atrLayers[i]);
  2903. if (pszEnvVar) {
  2904. wcscat(szFullEnvVar, pszEnvVar);
  2905. wcscat(szFullEnvVar, L" ");
  2906. }
  2907. //
  2908. // Keep counting the dlls.
  2909. //
  2910. trShimRef = SdbFindFirstTagRef(hSDB, psdbQuery->atrLayers[i], TAG_SHIM_REF);
  2911. while (trShimRef != TAGREF_NULL) {
  2912. (*lpdwShimsCount)++;
  2913. trShimRef = SdbFindNextTagRef(hSDB, psdbQuery->atrLayers[i], trShimRef);
  2914. }
  2915. }
  2916. //
  2917. // Set the layer environment variable if not set
  2918. //
  2919. if (szFullEnvVar[0] && psdbQuery->atrLayers[0]) {
  2920. SeiSetLayerEnvVar(szFullEnvVar);
  2921. }
  2922. }
  2923. BOOL
  2924. SeiGetShimCommandLine(
  2925. HSDB hSDB,
  2926. TAGREF trShimRef,
  2927. LPSTR lpszCmdLine
  2928. )
  2929. {
  2930. TAGREF trCmdLine;
  2931. WCHAR wszCmdLine[SHIM_COMMAND_LINE_MAX_BUFFER];
  2932. //
  2933. // Check for command line
  2934. //
  2935. lpszCmdLine[0] = 0;
  2936. trCmdLine = SdbFindFirstTagRef(hSDB, trShimRef, TAG_COMMAND_LINE);
  2937. if (trCmdLine == TAGREF_NULL) {
  2938. return FALSE;
  2939. }
  2940. wszCmdLine[0] = 0;
  2941. if (SdbReadStringTagRef(hSDB, trCmdLine, wszCmdLine, SHIM_COMMAND_LINE_MAX_BUFFER)) {
  2942. UNICODE_STRING UnicodeString;
  2943. ANSI_STRING AnsiString = { 0, SHIM_COMMAND_LINE_MAX_BUFFER, lpszCmdLine };
  2944. NTSTATUS status;
  2945. RtlInitUnicodeString(&UnicodeString, wszCmdLine);
  2946. status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  2947. //
  2948. // If conversion is unsuccessful, reset to zero-length string.
  2949. //
  2950. if (!NT_SUCCESS(status)) {
  2951. lpszCmdLine[0] = 0;
  2952. return FALSE;
  2953. }
  2954. }
  2955. return TRUE;
  2956. }
  2957. #ifndef SE_WIN2K
  2958. BOOL
  2959. SeiSetApphackFlags(
  2960. HSDB hSDB,
  2961. SDBQUERYRESULT* psdbQuery
  2962. )
  2963. {
  2964. ULARGE_INTEGER uliKernel;
  2965. ULARGE_INTEGER uliUser;
  2966. BOOL bUsingApphackFlags = FALSE;
  2967. PPEB Peb = NtCurrentPeb();
  2968. SdbQueryFlagMask(hSDB, psdbQuery, TAG_FLAG_MASK_KERNEL, &uliKernel.QuadPart, NULL);
  2969. SdbQueryFlagMask(hSDB, psdbQuery, TAG_FLAG_MASK_USER, &uliUser.QuadPart, NULL);
  2970. Peb->AppCompatFlags.QuadPart = uliKernel.QuadPart;
  2971. Peb->AppCompatFlagsUser.QuadPart = uliUser.QuadPart;
  2972. if (uliKernel.QuadPart != 0) {
  2973. DPF(dlPrint, "[SeiSetApphackFlags] Using kernel apphack flags 0x%x.\n", uliKernel.LowPart);
  2974. swprintf(g_szPipeData, L"%s - Using kernel apphack flags 0x%x",
  2975. g_szExeName,
  2976. uliKernel.LowPart);
  2977. SeiSendDataToPipe();
  2978. bUsingApphackFlags = TRUE;
  2979. }
  2980. if (uliUser.QuadPart != 0) {
  2981. DPF(dlPrint, "[SeiSetApphackFlags] Using user apphack flags 0x%x.\n", uliUser.LowPart);
  2982. swprintf(g_szPipeData, L"%s - Using user apphack flags 0x%x",
  2983. g_szExeName,
  2984. uliUser.LowPart);
  2985. SeiSendDataToPipe();
  2986. bUsingApphackFlags = TRUE;
  2987. }
  2988. return bUsingApphackFlags;
  2989. }
  2990. #endif
  2991. typedef struct tagTRSHIM {
  2992. TAGREF trShimRef;
  2993. BOOL bPlaceholder;
  2994. } TRSHIM, *PTRSHIM;
  2995. typedef struct tagTRSHIMARRAY {
  2996. int nShimRefCount;
  2997. int nShimRefMax;
  2998. TRSHIM* parrShimRef;
  2999. } TRSHIMARRAY, *PTRSHIMARRAY;
  3000. #define TR_DELTA 4
  3001. BOOL
  3002. SeiAddShim(
  3003. IN PTRSHIMARRAY pShimArray,
  3004. IN TAGREF trShimRef,
  3005. IN BOOL bPlaceholder
  3006. )
  3007. {
  3008. if (pShimArray->nShimRefCount >= pShimArray->nShimRefMax) {
  3009. PTRSHIM parrShimRef;
  3010. DWORD dwSize;
  3011. dwSize = (pShimArray->nShimRefMax + TR_DELTA) * sizeof(TRSHIM);
  3012. parrShimRef = (PTRSHIM)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  3013. HEAP_ZERO_MEMORY,
  3014. dwSize);
  3015. if (parrShimRef == NULL) {
  3016. DPF(dlError, "[SeiAddShim] Failed to allocate %d bytes.\n", dwSize);
  3017. return FALSE;
  3018. }
  3019. memcpy(parrShimRef, pShimArray->parrShimRef, pShimArray->nShimRefMax * sizeof(TRSHIM));
  3020. pShimArray->nShimRefMax += TR_DELTA;
  3021. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pShimArray->parrShimRef);
  3022. pShimArray->parrShimRef = parrShimRef;
  3023. }
  3024. pShimArray->parrShimRef[pShimArray->nShimRefCount].trShimRef = trShimRef;
  3025. pShimArray->parrShimRef[pShimArray->nShimRefCount].bPlaceholder = bPlaceholder;
  3026. (pShimArray->nShimRefCount)++;
  3027. return TRUE;
  3028. }
  3029. PTRSHIMARRAY
  3030. SeiBuildShimRefArray(
  3031. IN HSDB hSDB,
  3032. IN SDBQUERYRESULT* psdbQuery,
  3033. OUT LPDWORD lpdwShimCount,
  3034. IN BOOL bApplyExes,
  3035. IN BOOL bApplyToSystemExes,
  3036. IN BOOL bIsSetup
  3037. )
  3038. {
  3039. DWORD dw;
  3040. TAGREF trExe;
  3041. TAGREF trLayer;
  3042. TAGREF trShimRef;
  3043. DWORD dwShimsCount = 0;
  3044. WCHAR szFullEnvVar[MAX_PATH];
  3045. PTRSHIMARRAY pShimArray;
  3046. *lpdwShimCount = 0;
  3047. pShimArray = (PTRSHIMARRAY)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  3048. HEAP_ZERO_MEMORY,
  3049. sizeof(TRSHIMARRAY));
  3050. if (pShimArray == NULL) {
  3051. DPF(dlError, "[SeiBuildShimRefArray] Failed to allocate %d bytes.\n", sizeof(TRSHIMARRAY));
  3052. return NULL;
  3053. }
  3054. for (dw = 0; dw < SDB_MAX_EXES; dw++) {
  3055. trExe = psdbQuery->atrExes[dw];
  3056. if (trExe == TAGREF_NULL) {
  3057. break;
  3058. }
  3059. //
  3060. // Count the SHIMs that this EXE uses.
  3061. //
  3062. trShimRef = SdbFindFirstTagRef(hSDB, trExe, TAG_SHIM_REF);
  3063. while (trShimRef != TAGREF_NULL) {
  3064. SeiAddShim(pShimArray, trShimRef, FALSE);
  3065. dwShimsCount++;
  3066. trShimRef = SdbFindNextTagRef(hSDB, trExe, trShimRef);
  3067. }
  3068. }
  3069. //
  3070. // Count the DLLs that trLayer uses, and put together the environment variable
  3071. //
  3072. szFullEnvVar[0] = 0;
  3073. //
  3074. // Make sure to propagate the flags.
  3075. //
  3076. if (!bApplyExes) {
  3077. wcscat(szFullEnvVar, L"!");
  3078. }
  3079. if (bApplyToSystemExes) {
  3080. wcscat(szFullEnvVar, L"#");
  3081. }
  3082. for (dw = 0; dw < SDB_MAX_LAYERS && psdbQuery->atrLayers[dw] != TAGREF_NULL; dw++) {
  3083. WCHAR* pszEnvVar;
  3084. trLayer = psdbQuery->atrLayers[dw];
  3085. //
  3086. // Get the environment var and tack it onto the full string
  3087. //
  3088. pszEnvVar = SeiGetLayerName(hSDB, trLayer);
  3089. if (bIsSetup && !wcscmp(pszEnvVar, L"LUA")) {
  3090. //
  3091. // If the user is trying to apply the LUA layer to a setup program,
  3092. // we ignore it.
  3093. //
  3094. continue;
  3095. }
  3096. if (pszEnvVar) {
  3097. wcscat(szFullEnvVar, pszEnvVar);
  3098. wcscat(szFullEnvVar, L" ");
  3099. }
  3100. //
  3101. // Keep counting the shims.
  3102. //
  3103. trShimRef = SdbFindFirstTagRef(hSDB, trLayer, TAG_SHIM_REF);
  3104. while (trShimRef != TAGREF_NULL) {
  3105. SeiAddShim(pShimArray, trShimRef, FALSE);
  3106. dwShimsCount++;
  3107. trShimRef = SdbFindNextTagRef(hSDB, trLayer, trShimRef);
  3108. }
  3109. }
  3110. //
  3111. // Set the layer environment variable if not set
  3112. //
  3113. if (szFullEnvVar[0] && psdbQuery->atrLayers[0]) {
  3114. SeiSetLayerEnvVar(szFullEnvVar);
  3115. }
  3116. *lpdwShimCount = dwShimsCount;
  3117. return pShimArray;
  3118. }
  3119. BOOL
  3120. SeiIsSetup(
  3121. IN LPCWSTR pwszFullPath
  3122. )
  3123. {
  3124. WCHAR wszModuleName[MAX_PATH];
  3125. LPWSTR pwszModuleName = NULL;
  3126. wcsncpy(wszModuleName, pwszFullPath, MAX_PATH);
  3127. wszModuleName[MAX_PATH - 1] = 0;
  3128. pwszModuleName = wcsrchr(wszModuleName, L'\\') + 1;
  3129. _wcslwr(pwszModuleName);
  3130. if (wcsstr(pwszModuleName, L"setup") || wcsstr(pwszModuleName, L"install")) {
  3131. return TRUE;
  3132. } else {
  3133. LPWSTR pwsz;
  3134. if (pwsz = wcsstr(pwszModuleName, L"_ins")) {
  3135. if (wcsstr(pwsz + 4, L"_mp")) {
  3136. return TRUE;
  3137. }
  3138. }
  3139. }
  3140. return FALSE;
  3141. }
  3142. BOOL
  3143. SeiInit(
  3144. IN LPCWSTR pwszFullPath,
  3145. IN HSDB hSDB,
  3146. OUT SDBQUERYRESULT* psdbQuery,
  3147. IN LPCSTR lpszModuleToShim,
  3148. IN BOOL bDynamic
  3149. )
  3150. /*++
  3151. Return: TRUE on success, FALSE otherwise.
  3152. Desc: Injects all the shims and patches specified for this EXE
  3153. in the database.
  3154. --*/
  3155. {
  3156. PPEB Peb = NtCurrentPeb();
  3157. BOOL bResult = FALSE;
  3158. TAGREF trShimRef;
  3159. NTSTATUS status;
  3160. DWORD dwCounter = 0;
  3161. WCHAR wszDLLPath[MAX_PATH];
  3162. WCHAR wszShimName[MAX_PATH];
  3163. CHAR szCmdLine[SHIM_COMMAND_LINE_MAX_BUFFER];
  3164. DWORD dwTotalHooks = 0;
  3165. BOOL bApplyExes = TRUE;
  3166. BOOL bApplyToSystemExes = FALSE;
  3167. BOOL bUsingApphackFlags = FALSE;
  3168. DWORD dwAPIsHooked = 0;
  3169. DWORD dw;
  3170. DWORD dwShimsCount = 0;
  3171. PHOOKAPI* pHookArray = NULL;
  3172. PSHIMINFO pShimInfo;
  3173. int nShimRef;
  3174. PTRSHIMARRAY pShimArray = NULL;
  3175. BOOL bIsSetup;
  3176. g_bShimDuringInit = TRUE;
  3177. #ifndef SE_WIN2K
  3178. if (!bDynamic) {
  3179. //
  3180. // Mark almost all loaded DLLs as if they already run their init routines.
  3181. //
  3182. SeiSetEntryProcessed(Peb);
  3183. if (psdbQuery->trAppHelp) {
  3184. if (!SeiDisplayAppHelp(hSDB, psdbQuery)) {
  3185. //
  3186. // We should never end up here because SeiDisplayApphelp
  3187. // calls TerminateProcess before returning FALSE.
  3188. //
  3189. goto cleanup;
  3190. }
  3191. }
  3192. }
  3193. #endif // SE_WIN2K
  3194. bIsSetup = SeiIsSetup(pwszFullPath);
  3195. if (!SeiInitGlobals(pwszFullPath)) {
  3196. DPF(dlError, "[SeiInit] Failed to initialize global data\n");
  3197. goto cleanup;
  3198. }
  3199. SeiLayersCheck(pwszFullPath, &bApplyExes, &bApplyToSystemExes, psdbQuery);
  3200. //
  3201. // This should be taken care of by apphelp, but
  3202. // we're taking a belt-and-suspenders approach here.
  3203. //
  3204. if (!bApplyExes) {
  3205. psdbQuery->atrExes[0] = TAGREF_NULL;
  3206. }
  3207. pShimArray = SeiBuildShimRefArray(hSDB,
  3208. psdbQuery,
  3209. &dwShimsCount,
  3210. bApplyExes,
  3211. bApplyToSystemExes,
  3212. bIsSetup);
  3213. if (pShimArray == NULL) {
  3214. DPF(dlError, "[SeiInit] Failed to build the shimref array\n");
  3215. goto cleanup;
  3216. }
  3217. //
  3218. // Set some global variables so we'll know if we're using a layer,
  3219. // an exe entry, or both.
  3220. //
  3221. // These variables are only used for debug purposes.
  3222. //
  3223. if (psdbQuery->atrExes[0] != TAGREF_NULL) {
  3224. g_bUsingExe = TRUE;
  3225. }
  3226. if (psdbQuery->atrLayers[0] != TAGREF_NULL) {
  3227. g_bUsingLayer = TRUE;
  3228. }
  3229. //
  3230. // Debug spew for matching notification.
  3231. //
  3232. DPF(dlPrint, "[SeiInit] Matched entry: \"%S\"\n", pwszFullPath);
  3233. //
  3234. // Send the name of the process to the pipe
  3235. //
  3236. swprintf(g_szPipeData, L"New process created: %s", pwszFullPath);
  3237. SeiSendDataToPipe();
  3238. #ifndef SE_WIN2K
  3239. //
  3240. // Get the apphack flags. These can only be enabled if the shimengine is not
  3241. // dynamically initialized.
  3242. //
  3243. if (!bDynamic && !(bUsingApphackFlags = SeiSetApphackFlags(hSDB, psdbQuery))) {
  3244. DPF(dlPrint, "[SeiInit] No apphack flags for this app \"%S\".\n", pwszFullPath);
  3245. }
  3246. #endif // SE_WIN2K
  3247. //
  3248. // See if there are any shims.
  3249. //
  3250. if (dwShimsCount == 0) {
  3251. DPF(dlPrint, "[SeiInit] No new SHIMs for this app \"%S\".\n", pwszFullPath);
  3252. goto OnlyPatches;
  3253. }
  3254. //
  3255. // We need to load the global inclusion/exclusion list if any.
  3256. //
  3257. SeiBuildGlobalInclList(hSDB);
  3258. if (g_dwShimsCount == 0) {
  3259. //
  3260. // Increment the shims count to allow for our internal stubs.
  3261. // Also reserve space for up to MAX_DYNAMIC_SHIMS more dynamic shims.
  3262. //
  3263. dwShimsCount++;
  3264. g_dwMaxShimsCount = dwShimsCount + MAX_DYNAMIC_SHIMS;
  3265. //
  3266. // Allocate a storage pointer for the hook information.
  3267. //
  3268. g_pHookArray = (PHOOKAPI*)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  3269. HEAP_ZERO_MEMORY,
  3270. sizeof(PHOOKAPI) * g_dwMaxShimsCount);
  3271. if (g_pHookArray == NULL) {
  3272. DPF(dlError,
  3273. "[SeiInit] Failure allocating %d bytes for the hook array\n",
  3274. sizeof(PHOOKAPI) * g_dwMaxShimsCount);
  3275. goto cleanup;
  3276. }
  3277. //
  3278. // Allocate the array that keeps information about the shims.
  3279. //
  3280. g_pShimInfo = (PSHIMINFO)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  3281. HEAP_ZERO_MEMORY,
  3282. sizeof(SHIMINFO) * g_dwMaxShimsCount);
  3283. if (g_pShimInfo == NULL) {
  3284. DPF(dlError,
  3285. "[SeiInit] Failure allocating %d bytes for the SHIMINFO array\n",
  3286. sizeof(SHIMINFO) * g_dwMaxShimsCount);
  3287. goto cleanup;
  3288. }
  3289. //
  3290. // Point the local variables to the beginning of the arrays.
  3291. //
  3292. pHookArray = g_pHookArray;
  3293. pShimInfo = g_pShimInfo;
  3294. } else {
  3295. if (g_dwShimsCount + dwShimsCount >= g_dwMaxShimsCount) {
  3296. DPF(dlError, "[SeiInit] Too many shims\n");
  3297. goto cleanup;
  3298. }
  3299. //
  3300. // Point the local variables to the end of the existing arrays.
  3301. //
  3302. pHookArray = g_pHookArray + g_dwShimsCount;
  3303. pShimInfo = g_pShimInfo + g_dwShimsCount;
  3304. }
  3305. //
  3306. // Get the first shim.
  3307. //
  3308. nShimRef = 0;
  3309. while (nShimRef < pShimArray->nShimRefCount) {
  3310. PVOID pModuleHandle = NULL;
  3311. UNICODE_STRING UnicodeString;
  3312. ANSI_STRING ProcedureNameString;
  3313. PFNGETHOOKAPIS pfnGetHookApis = NULL;
  3314. TAGREF trShimName = TAGREF_NULL;
  3315. LPWSTR pwszDllShortName;
  3316. DWORD i, dwShimIndex;
  3317. trShimRef = pShimArray->parrShimRef[nShimRef].trShimRef;
  3318. //
  3319. // Retrieve the shim name.
  3320. //
  3321. wszShimName[0] = 0;
  3322. trShimName = SdbFindFirstTagRef(hSDB, trShimRef, TAG_NAME);
  3323. if (trShimName == TAGREF_NULL) {
  3324. DPF(dlError, "[SeiInit] Could not retrieve shim name tag from entry.\n");
  3325. goto cleanup;
  3326. }
  3327. if (!SdbReadStringTagRef(hSDB, trShimName, wszShimName, MAX_PATH)) {
  3328. DPF(dlError, "[SeiInit] Could not retrieve shim name from entry.\n");
  3329. goto cleanup;
  3330. }
  3331. //
  3332. // Check for duplicate shims.
  3333. //
  3334. for (i = 0; i < g_dwShimsCount + dwCounter; ++i) {
  3335. if (_wcsnicmp(g_pShimInfo[i].wszName, wszShimName, MAX_SHIM_NAME_LEN) == 0) {
  3336. dwShimIndex = i;
  3337. goto nextShim;
  3338. }
  3339. }
  3340. //
  3341. // Save off the name of the shim.
  3342. //
  3343. wcsncpy(pShimInfo[dwCounter].wszName, wszShimName, MAX_SHIM_NAME_LEN);
  3344. pShimInfo[dwCounter].wszName[MAX_SHIM_NAME_LEN] = 0;
  3345. if (!SdbGetDllPath(hSDB, trShimRef, wszDLLPath)) {
  3346. DPF(dlError, "[SeiInit] Failed to get DLL Path\n");
  3347. goto cleanup;
  3348. }
  3349. pwszDllShortName = SeiGetShortName(wszDLLPath);
  3350. RtlInitUnicodeString(&UnicodeString, wszDLLPath);
  3351. //
  3352. // Check if we already loaded this DLL.
  3353. //
  3354. status = LdrGetDllHandle(NULL,
  3355. NULL,
  3356. &UnicodeString,
  3357. &pModuleHandle);
  3358. if (!NT_SUCCESS(status)) {
  3359. //
  3360. // Load the DLL that hosts this shim.
  3361. //
  3362. #ifndef SE_WIN2K
  3363. //
  3364. // Save the name of the DLL that we're about to load so we don't screw
  3365. // it's init routine.
  3366. //
  3367. wcscpy(g_wszShimDllInLoading, pwszDllShortName);
  3368. #endif // SE_WIN2K
  3369. status = LdrLoadDll(UNICODE_NULL, NULL, &UnicodeString, &pModuleHandle);
  3370. if (!NT_SUCCESS(status)) {
  3371. DPF(dlError,
  3372. "[SeiInit] Failed to load DLL \"%S\" Status 0x%lx\n",
  3373. wszDLLPath, status);
  3374. goto cleanup;
  3375. }
  3376. DPF(dlPrint,
  3377. "[SeiInit] Shim DLL 0x%X \"%S\" loaded\n",
  3378. pModuleHandle,
  3379. wszDLLPath);
  3380. }
  3381. DPF(dlPrint, "[SeiInit] Using SHIM \"%S!%S\"\n",
  3382. wszShimName, pwszDllShortName);
  3383. pShimInfo[dwCounter].pDllBase = pModuleHandle;
  3384. //
  3385. // Check for command line.
  3386. //
  3387. if (SeiGetShimCommandLine(hSDB, trShimRef, szCmdLine)) {
  3388. DPF(dlPrint,
  3389. "[SeiInit] Command line for Shim \"%S\" : \"%s\"\n",
  3390. wszShimName,
  3391. szCmdLine);
  3392. }
  3393. //
  3394. // Send this shim name to the pipe
  3395. //
  3396. swprintf(g_szPipeData,
  3397. L"%s - Applying shim %s(%S) from %s",
  3398. g_szExeName,
  3399. wszShimName,
  3400. szCmdLine,
  3401. pwszDllShortName);
  3402. SeiSendDataToPipe();
  3403. //
  3404. // Get the GetHookApis entry point.
  3405. //
  3406. RtlInitString(&ProcedureNameString, "GetHookAPIs");
  3407. status = LdrGetProcedureAddress(pModuleHandle,
  3408. &ProcedureNameString,
  3409. 0,
  3410. (PVOID*)&pfnGetHookApis);
  3411. if (!NT_SUCCESS(status) || pfnGetHookApis == NULL) {
  3412. DPF(dlError,
  3413. "[SeiInit] Failed to get 'GetHookAPIs' address, DLL \"%S\"\n",
  3414. wszDLLPath);
  3415. goto cleanup;
  3416. }
  3417. dwTotalHooks = 0;
  3418. //
  3419. // Call the proc and then store away its hook params.
  3420. //
  3421. pHookArray[dwCounter] = (*pfnGetHookApis)(szCmdLine, wszShimName, &dwTotalHooks);
  3422. dwAPIsHooked += dwTotalHooks;
  3423. DPF(dlInfo,
  3424. "[SeiInit] GetHookAPIs returns %d hooks for DLL \"%S\" SHIM \"%S\"\n",
  3425. dwTotalHooks, wszDLLPath, wszShimName);
  3426. pShimInfo[dwCounter].dwHookedAPIs = dwTotalHooks;
  3427. pShimInfo[dwCounter].pLdrEntry = SeiGetLoaderEntry(Peb, pModuleHandle);
  3428. if (dwTotalHooks > 0) {
  3429. //
  3430. // Initialize the HOOKAPIEX structure.
  3431. //
  3432. for (i = 0; i < dwTotalHooks; ++i) {
  3433. PHOOKAPIEX pHookEx;
  3434. pHookEx = (PHOOKAPIEX)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  3435. HEAP_ZERO_MEMORY,
  3436. sizeof(HOOKAPIEX));
  3437. if (!pHookEx) {
  3438. DPF(dlError,
  3439. "[SeiInit] Failed to allocate %d bytes (HOOKAPIEX)\n",
  3440. sizeof(HOOKAPIEX));
  3441. goto cleanup;
  3442. }
  3443. pHookArray[dwCounter][i].pHookEx = pHookEx;
  3444. pHookArray[dwCounter][i].pHookEx->dwShimID = g_dwShimsCount + dwCounter;
  3445. }
  3446. #if DBG
  3447. //
  3448. // Give a debugger warning if uninitialized HOOKAPI structures
  3449. // are used.
  3450. //
  3451. {
  3452. DWORD dwUninitCount = 0;
  3453. for (i = 0; i < dwTotalHooks; ++i) {
  3454. if (pHookArray[dwCounter][i].pszModule == NULL ||
  3455. pHookArray[dwCounter][i].pszFunctionName == NULL) {
  3456. dwUninitCount++;
  3457. }
  3458. }
  3459. if (dwUninitCount > 0) {
  3460. DPF(dlWarning,
  3461. "[SeiInit] Shim \"%S\" using %d uninitialized HOOKAPI structures.\n",
  3462. pShimInfo[dwCounter].wszName, dwUninitCount);
  3463. }
  3464. }
  3465. #endif // DBG
  3466. }
  3467. dwShimIndex = g_dwShimsCount + dwCounter;
  3468. dwCounter++;
  3469. nextShim:
  3470. //
  3471. // Read the inclusion/exclusion list for this shim.
  3472. //
  3473. if (bDynamic && lpszModuleToShim != NULL) {
  3474. if (!SeiBuildInclListWithOneModule(dwShimIndex, lpszModuleToShim)) {
  3475. DPF(dlError,
  3476. "[SeiInit] Couldn't build the inclusion list w/ one module for Shim \"%S\"\n",
  3477. wszShimName);
  3478. goto cleanup;
  3479. }
  3480. } else {
  3481. if (!SeiBuildInclExclList(hSDB, trShimRef, dwShimIndex, pwszFullPath)) {
  3482. DPF(dlError,
  3483. "[SeiInit] Couldn't build the inclusion/exclusion list for Shim \"%S\"\n",
  3484. wszShimName);
  3485. goto cleanup;
  3486. }
  3487. }
  3488. //
  3489. // Go to the next shim ref.
  3490. //
  3491. nShimRef++;
  3492. }
  3493. if (dwAPIsHooked > 0) {
  3494. //
  3495. // We need to add our internal hooks
  3496. //
  3497. if (SeiAddInternalHooks(dwCounter)) {
  3498. dwCounter++;
  3499. }
  3500. }
  3501. //
  3502. // Update the shim counter.
  3503. //
  3504. g_dwShimsCount += dwCounter;
  3505. OnlyPatches:
  3506. for (dw = 0; dw < SDB_MAX_EXES; dw++) {
  3507. if (psdbQuery->atrExes[dw] == TAGREF_NULL) {
  3508. break;
  3509. }
  3510. //
  3511. // Loop through available in-memory patches for this EXE.
  3512. //
  3513. SeiLoadPatches(hSDB, psdbQuery->atrExes[dw]);
  3514. }
  3515. if (g_dwMemoryPatchCount == 0) {
  3516. DPF(dlPrint, "[SeiInit] No patches for this app \"%S\".\n", pwszFullPath);
  3517. }
  3518. if (g_dwMemoryPatchCount == 0 && g_dwShimsCount == 0 && !bUsingApphackFlags) {
  3519. DPF(dlError, "[SeiInit] No fixes in the DB for this app \"%S\".\n", pwszFullPath);
  3520. goto cleanup;
  3521. }
  3522. //
  3523. // Walk the hook list and fixup available APIs
  3524. //
  3525. if (!PatchNewModules(bDynamic)) {
  3526. DPF(dlError, "[SeiInit] Unsuccessful fixing up APIs, EXE \"%S\"\n", pwszFullPath);
  3527. goto cleanup;
  3528. }
  3529. //
  3530. // Notify the shims that static link DLLs have run their init routine.
  3531. //
  3532. if (bDynamic) {
  3533. NotifyShims(SN_STATIC_DLLS_INITIALIZED, 1);
  3534. }
  3535. //
  3536. // The shim has successfuly initialized
  3537. //
  3538. g_bShimInitialized = TRUE;
  3539. bResult = TRUE;
  3540. cleanup:
  3541. //
  3542. // Cleanup
  3543. //
  3544. if (pShimArray) {
  3545. if (pShimArray->parrShimRef) {
  3546. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pShimArray->parrShimRef);
  3547. }
  3548. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pShimArray);
  3549. }
  3550. if (!bDynamic) {
  3551. //
  3552. // We can pass back any one of the exes. The first is fine.
  3553. //
  3554. if (psdbQuery->atrExes[0] != TAGREF_NULL) {
  3555. SdbReleaseMatchingExe(hSDB, psdbQuery->atrExes[0]);
  3556. }
  3557. if (hSDB != NULL) {
  3558. SdbReleaseDatabase(hSDB);
  3559. }
  3560. #ifndef SE_WIN2K
  3561. SeiResetEntryProcessed(Peb);
  3562. #endif // SE_WIN2K
  3563. }
  3564. g_bShimDuringInit = FALSE;
  3565. if (!bResult) {
  3566. #if DBG
  3567. if (!bUsingApphackFlags) {
  3568. DbgPrint("[SeiInit] Shim engine failed to initialize.\n");
  3569. }
  3570. #endif // DBG
  3571. //
  3572. // Unload the shim DLLs that are loaded so far.
  3573. //
  3574. // Don't do this during dynamic shimming.
  3575. //
  3576. if (!bDynamic) {
  3577. if (g_pShimInfo != NULL) {
  3578. for (dwCounter = 0; dwCounter < g_dwShimsCount; dwCounter++) {
  3579. if (g_pShimInfo[dwCounter].pDllBase == NULL) {
  3580. break;
  3581. }
  3582. LdrUnloadDll(g_pShimInfo[dwCounter].pDllBase);
  3583. }
  3584. }
  3585. if (g_pShimHeap != NULL) {
  3586. RtlDestroyHeap(g_pShimHeap);
  3587. g_pShimHeap = NULL;
  3588. }
  3589. }
  3590. }
  3591. return bResult;
  3592. }
  3593. HSDB
  3594. SeiGetShimData(
  3595. IN PPEB Peb,
  3596. IN PVOID pShimData,
  3597. OUT LPWSTR pwszFullPath, // this is supplied on Whistler and returned on Win2k
  3598. OUT SDBQUERYRESULT* psdbQuery
  3599. )
  3600. {
  3601. HSDB hSDB = NULL;
  3602. BOOL bResult;
  3603. #ifdef DEBUG_SPEW
  3604. SeiInitDebugSupport();
  3605. #endif // DEBUG_SPEW
  3606. //
  3607. // Get the name of the executable being run.
  3608. //
  3609. if (!SeiGetExeName(Peb, pwszFullPath)) {
  3610. DPF(dlError, "[SeiGetShimData] Can't get EXE name\n");
  3611. return NULL;
  3612. }
  3613. if (!_wcsicmp(g_szExeName, L"ntsd.exe") ||
  3614. !_wcsicmp(g_szExeName, L"windbg.exe")) {
  3615. DPF(dlPrint, "[SeiGetShimData] not shimming ntsd.exe\n");
  3616. return NULL;
  3617. }
  3618. //
  3619. // Open up the Database and see if there's any blob information about this EXE.
  3620. //
  3621. hSDB = SdbInitDatabase(0, NULL);
  3622. if (hSDB == NULL) {
  3623. DPF(dlError, "[SeiGetShimData] Can't open shim DB.\n");
  3624. return NULL;
  3625. }
  3626. //
  3627. // Ensure that the sdbQuery starts out clean.
  3628. //
  3629. ZeroMemory(psdbQuery, sizeof(SDBQUERYRESULT));
  3630. #ifdef SE_WIN2K
  3631. bResult = SdbGetMatchingExe(hSDB, pwszFullPath, NULL, NULL, 0, psdbQuery);
  3632. #else
  3633. bResult = SdbUnpackAppCompatData(hSDB, pwszFullPath, pShimData, psdbQuery);
  3634. #endif // SE_WIN2K
  3635. if (!bResult) {
  3636. DPF(dlError, "[SeiGetShimData] Can't get EXE data\n");
  3637. goto failure;
  3638. }
  3639. return hSDB;
  3640. failure:
  3641. SdbReleaseDatabase(hSDB);
  3642. return NULL;
  3643. }
  3644. #ifdef SE_WIN2K
  3645. BOOL
  3646. LoadPatchDll(
  3647. IN LPCSTR pszCmdLine // The command line from the registry.
  3648. // Unused parameter.
  3649. )
  3650. /*++
  3651. Return: TRUE on success, FALSE otherwise. However user32.dll ignores the return
  3652. value of this function.
  3653. Desc: This function is called from user32.dll to initialize the shim engine.
  3654. It queries the shim database and loads all the shim DLLs and patches that
  3655. are available for this EXE.
  3656. --*/
  3657. {
  3658. PPEB Peb = NtCurrentPeb();
  3659. WCHAR wszFullPath[MAX_PATH];
  3660. HSDB hSDB;
  3661. SDBQUERYRESULT sdbQuery;
  3662. hSDB = SeiGetShimData(Peb, NULL, wszFullPath, &sdbQuery);
  3663. if (hSDB == NULL) {
  3664. DPF(dlError, "[LoadPatchDll] Failed to get shim data\n");
  3665. return FALSE;
  3666. }
  3667. return SeiInit(wszFullPath, hSDB, &sdbQuery, NULL, FALSE);
  3668. }
  3669. #else
  3670. BOOL
  3671. SeiDisplayAppHelp(
  3672. IN HSDB hSDB,
  3673. IN PSDBQUERYRESULT pSdbQuery
  3674. )
  3675. /*++
  3676. Return: void
  3677. Desc: This function launches apphelp for the starting EXE.
  3678. --*/
  3679. {
  3680. PDB pdb;
  3681. TAGID tiExe;
  3682. GUID guidDB;
  3683. WCHAR wszGuid[MAX_PATH];
  3684. WCHAR wszCommandLine[MAX_PATH];
  3685. DWORD dwExit;
  3686. char szName[50];
  3687. PVOID hModule, pAddress;
  3688. WCHAR wszTemp[MAX_PATH];
  3689. UNICODE_STRING ustrTemp;
  3690. UNICODE_STRING ustrGuid;
  3691. ANSI_STRING strName;
  3692. STARTUPINFOW StartupInfo;
  3693. PROCESS_INFORMATION ProcessInfo;
  3694. //
  3695. // If we have any errors along the way, go ahead and run the app.
  3696. //
  3697. if (!SdbTagRefToTagID(hSDB, pSdbQuery->trAppHelp, &pdb, &tiExe)) {
  3698. DPF(dlError, "[SeiDisplayAppHelp] Failed to convert tagref to tagid.\n");
  3699. return TRUE;
  3700. }
  3701. if (!SdbGetDatabaseGUID(hSDB, pdb, &guidDB)) {
  3702. DPF(dlError, "[SeiDisplayAppHelp] Failed to get DB guid.\n");
  3703. return TRUE;
  3704. }
  3705. ustrGuid.Buffer = wszGuid;
  3706. ustrGuid.Length = 0;
  3707. ustrGuid.MaximumLength = MAX_PATH;
  3708. if (RtlStringFromGUID(&guidDB, &ustrGuid) != STATUS_SUCCESS) {
  3709. DPF(dlError, "[SeiDisplayAppHelp] Failed to convert guid to string.\n");
  3710. return TRUE;
  3711. }
  3712. swprintf(wszCommandLine, L"ahui.exe %s 0x%x", ustrGuid.Buffer, tiExe);
  3713. //
  3714. // We need a hack here to get kernel32.dll to initialize. We load aclayers.dll
  3715. // to trigger the init routine of kernel32.
  3716. //
  3717. SdbpGetAppPatchDir(wszTemp);
  3718. wcscat(wszTemp, L"\\aclayers.dll");
  3719. RtlInitUnicodeString(&ustrTemp, wszTemp);
  3720. //
  3721. // Save the name of the DLL that we're about to load so we don't screw
  3722. // it's init routine.
  3723. //
  3724. wcscpy(g_wszShimDllInLoading, L"aclayers.dll");
  3725. LdrLoadDll(UNICODE_NULL, NULL, &ustrTemp, &hModule);
  3726. g_hApphelpDllHelper = hModule;
  3727. RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
  3728. RtlZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
  3729. StartupInfo.cb = sizeof(StartupInfo);
  3730. if (!CreateProcessW(NULL, wszCommandLine, NULL, NULL, FALSE, 0, NULL, NULL,
  3731. &StartupInfo, &ProcessInfo)) {
  3732. DPF(dlError, "[SeiDisplayAppHelp] Failed to launch apphelp process.\n");
  3733. return TRUE;
  3734. }
  3735. WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
  3736. GetExitCodeProcess(ProcessInfo.hProcess, &dwExit);
  3737. if (!dwExit) {
  3738. SeiResetEntryProcessed(NtCurrentPeb());
  3739. TerminateProcess(GetCurrentProcess(), 0);
  3740. return FALSE;
  3741. }
  3742. return TRUE;
  3743. }
  3744. #ifdef SE_WIN2K
  3745. #define SeiCheckComPlusImage(Peb)
  3746. #else
  3747. void
  3748. SeiCheckComPlusImage(
  3749. PPEB Peb
  3750. )
  3751. {
  3752. PIMAGE_NT_HEADERS NtHeader;
  3753. ULONG Cor20HeaderSize;
  3754. NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
  3755. g_bComPlusImage = FALSE;
  3756. g_bComPlusImage = (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
  3757. TRUE,
  3758. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
  3759. &Cor20HeaderSize) != NULL);
  3760. DPF(dlPrint, "[SeiCheckComPlusImage] COM+ executable %s\n",
  3761. (g_bComPlusImage ? "TRUE" : "FALSE"));
  3762. }
  3763. #endif // SE_WIN2K
  3764. void
  3765. SE_InstallBeforeInit(
  3766. IN PUNICODE_STRING pstrFullPath, // The name of the starting EXE
  3767. IN PVOID pShimExeData // The pointer provided by apphelp.dll
  3768. )
  3769. /*++
  3770. Return: void
  3771. Desc: This function installs the shim support for the starting EXE.
  3772. --*/
  3773. {
  3774. PPEB Peb = NtCurrentPeb();
  3775. HSDB hSDB;
  3776. SDBQUERYRESULT sdbQuery;
  3777. hSDB = SeiGetShimData(Peb, pShimExeData, pstrFullPath->Buffer, &sdbQuery);
  3778. if (hSDB == NULL) {
  3779. DPF(dlError, "[SE_InstallBeforeInit] Failed to get shim data\n");
  3780. return;
  3781. }
  3782. //
  3783. // Check if the image is a COM+ image
  3784. //
  3785. SeiCheckComPlusImage(Peb);
  3786. SeiInit(pstrFullPath->Buffer, hSDB, &sdbQuery, NULL, FALSE);
  3787. if (pShimExeData != NULL) {
  3788. SIZE_T dwSize;
  3789. dwSize = SdbGetAppCompatDataSize(pShimExeData);
  3790. if (dwSize > 0) {
  3791. NtFreeVirtualMemory(NtCurrentProcess(),
  3792. &pShimExeData,
  3793. &dwSize,
  3794. MEM_RELEASE);
  3795. }
  3796. }
  3797. return;
  3798. }
  3799. #endif // SE_WIN2K
  3800. #ifndef SE_WIN2K
  3801. void
  3802. SE_ProcessDying(
  3803. void
  3804. )
  3805. {
  3806. NotifyShims(SN_PROCESS_DYING, 0);
  3807. return;
  3808. }
  3809. #endif // SE_WIN2K
  3810. BOOL
  3811. SE_DynamicShim(
  3812. IN LPCWSTR lpszFullPath,
  3813. IN HSDB hSDB,
  3814. IN SDBQUERYRESULT* psdbQuery,
  3815. IN LPCSTR lpszModuleToShim
  3816. )
  3817. /*++
  3818. Return: TRUE on success, FALSE otherwise.
  3819. Desc: This function attempts to inject shims dynamically.
  3820. --*/
  3821. {
  3822. SeiInitDebugSupport();
  3823. if (lpszModuleToShim != NULL && *lpszModuleToShim == 0) {
  3824. lpszModuleToShim = NULL;
  3825. }
  3826. SeiInit(lpszFullPath, hSDB, psdbQuery, lpszModuleToShim, TRUE);
  3827. #ifndef SE_WIN2K
  3828. LdrInitShimEngineDynamic(g_hModule);
  3829. #endif
  3830. return TRUE;
  3831. }
  3832. BOOL
  3833. SeiSendDataToPipe(
  3834. void
  3835. )
  3836. {
  3837. OBJECT_ATTRIBUTES ObjA;
  3838. FILE_PIPE_INFORMATION fpi;
  3839. UNICODE_STRING uName;
  3840. IO_STATUS_BLOCK ioStatusBlock;
  3841. HANDLE hPipe;
  3842. NTSTATUS status;
  3843. LARGE_INTEGER liOffset;
  3844. ULONG uBytes;
  3845. DWORD dwRet, dwCount;
  3846. RtlInitUnicodeString(&uName, PIPE_NAME);
  3847. InitializeObjectAttributes(&ObjA,
  3848. &uName,
  3849. OBJ_CASE_INSENSITIVE,
  3850. NULL,
  3851. NULL);
  3852. ioStatusBlock.Status = 0;
  3853. ioStatusBlock.Information = 0;
  3854. //
  3855. // Open the named pipe
  3856. //
  3857. status = NtCreateFile(&hPipe,
  3858. FILE_GENERIC_WRITE,
  3859. &ObjA,
  3860. &ioStatusBlock,
  3861. NULL,
  3862. FILE_ATTRIBUTE_NORMAL,
  3863. 0,
  3864. FILE_OPEN,
  3865. 0,
  3866. NULL,
  3867. 0);
  3868. if ((!NT_SUCCESS(status) || INVALID_HANDLE_VALUE == hPipe)) {
  3869. dwRet = RtlNtStatusToDosError(status);
  3870. DPF(dlError,
  3871. "[SeiSendDataToPipe] Failed to open named pipe. Error code: %d\n",
  3872. dwRet);
  3873. return FALSE;
  3874. }
  3875. //
  3876. // Change the mode of the named pipe to message mode
  3877. //
  3878. fpi.ReadMode = FILE_PIPE_MESSAGE_MODE;
  3879. fpi.CompletionMode = FILE_PIPE_QUEUE_OPERATION;
  3880. status = NtSetInformationFile(hPipe,
  3881. &ioStatusBlock,
  3882. &fpi,
  3883. sizeof(FILE_PIPE_INFORMATION),
  3884. FilePipeInformation);
  3885. if (!NT_SUCCESS(status)) {
  3886. dwRet = RtlNtStatusToDosError(status);
  3887. DPF(dlError,
  3888. "[SeiSendDataToPipe] Failed to change handle state. Error code: %d\n",
  3889. dwRet);
  3890. return FALSE;
  3891. }
  3892. ioStatusBlock.Status = 0;
  3893. ioStatusBlock.Information = 0;
  3894. liOffset.LowPart = 0;
  3895. liOffset.HighPart = 0;
  3896. //
  3897. // Send the data to the named pipe
  3898. //
  3899. uBytes = wcslen(g_szPipeData) * sizeof(WCHAR);
  3900. status = NtWriteFile(hPipe,
  3901. NULL,
  3902. NULL,
  3903. NULL,
  3904. &ioStatusBlock,
  3905. (PVOID)g_szPipeData,
  3906. uBytes,
  3907. &liOffset,
  3908. NULL);
  3909. if (!NT_SUCCESS(status)) {
  3910. dwRet = RtlNtStatusToDosError(status);
  3911. DPF(dlError,
  3912. "[SeiSendDataToPipe] Failed to send data. Error code: %d\n",
  3913. dwRet);
  3914. NtClose(hPipe);
  3915. return FALSE;
  3916. }
  3917. NtClose(hPipe);
  3918. return TRUE;
  3919. }
  3920. BOOL WINAPI
  3921. DllMain(
  3922. HINSTANCE hInstance,
  3923. DWORD dwreason,
  3924. LPVOID reserved
  3925. )
  3926. {
  3927. //
  3928. // The init routine for DLL_PROCESS_ATTACH will NEVER be called because
  3929. // ntdll calls LdrpLoadDll for this shim engine w/o calling the init routine.
  3930. // Look in ntdll\ldrinit.c LdrpLoadShimEngine.
  3931. // The only case when we will have hInstance is when we are loaded dynamically
  3932. //
  3933. if (dwreason == DLL_PROCESS_ATTACH) {
  3934. g_hModule = (HMODULE)hInstance;
  3935. }
  3936. return TRUE;
  3937. UNREFERENCED_PARAMETER(reserved);
  3938. }