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

3635 lines
112 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ShimEngV.c
  5. Abstract:
  6. This module implements the shim hooking using vectored exception handling
  7. Author:
  8. John Whited (v-johnwh) 13-Oct-1999
  9. Revision History:
  10. Corneliu Lupu (clupu) 18-Jul-2000 - make it a separate shim engine
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <string.h>
  16. #include <windef.h>
  17. #include <winbase.h>
  18. #include <stdio.h>
  19. #include <apcompat.h>
  20. #include "shimdb.h"
  21. #include "ShimEngV.h"
  22. //
  23. // Global function hooks the shim uses to keep from recursing itself
  24. //
  25. HOOKAPI g_InternalHookArray[2];
  26. PFNLDRLOADDLL g_pfnOldLdrLoadDLL;
  27. PFNLDRLOADDLL g_pfnLdrLoadDLL;
  28. PFNLDRUNLOADDLL g_pfnLdrUnloadDLL;
  29. PFNLDRUNLOADDLL g_pfnOldLdrUnloadDLL;
  30. PFNRTLALLOCATEHEAP g_pfnRtlAllocateHeap;
  31. PFNRTLFREEHEAP g_pfnRtlFreeHeap;
  32. //
  33. // Shim doesn't share the same heap the apps use
  34. //
  35. PVOID g_pShimHeap;
  36. //
  37. // Data used for the shim call stack
  38. //
  39. static DWORD dwCallArray[1];
  40. SHIMRET fnHandleRet[1];
  41. BOOL g_bDbgPrintEnabled;
  42. #define DEBUG_SPEW
  43. #ifdef DEBUG_SPEW
  44. #define DPF(_x_) \
  45. { \
  46. if (g_bDbgPrintEnabled) { \
  47. DbgPrint _x_ ; \
  48. } \
  49. }
  50. #else
  51. #define DPF
  52. #endif // DEBUG_SPEW
  53. DWORD
  54. GetInstructionLengthFromAddress(
  55. PVOID paddr);
  56. #ifdef DEBUG_SPEW
  57. void
  58. SevInitDebugSupport(
  59. void
  60. )
  61. /*++
  62. Params: void
  63. Return: void
  64. Desc: This function initializes g_bDbgPrintEnabled based on an env variable
  65. --*/
  66. {
  67. NTSTATUS status;
  68. UNICODE_STRING EnvName;
  69. UNICODE_STRING EnvValue;
  70. WCHAR wszEnvValue[128];
  71. RtlInitUnicodeString(&EnvName, L"SHIMENG_DEBUG_LEVEL");
  72. EnvValue.Buffer = wszEnvValue;
  73. EnvValue.Length = 0;
  74. EnvValue.MaximumLength = sizeof(wszEnvValue);
  75. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  76. if (NT_SUCCESS(status)) {
  77. g_bDbgPrintEnabled = TRUE;
  78. }
  79. }
  80. #endif // DEBUG_SPEW
  81. BOOL
  82. SevInitFileLog(
  83. PUNICODE_STRING pstrAppName
  84. )
  85. /*++
  86. Params: pstrAppName The full path of the starting EXE
  87. Return: TRUE if the log was
  88. Desc: This function checks an environment variable to determine if logging
  89. is enabled. If so, it will append a header that tells a new app is
  90. started.
  91. --*/
  92. {
  93. NTSTATUS status;
  94. UNICODE_STRING EnvName;
  95. UNICODE_STRING EnvValue;
  96. UNICODE_STRING FilePath;
  97. UNICODE_STRING NtSystemRoot;
  98. WCHAR wszEnvValue[128];
  99. WCHAR wszLogFile[MAX_PATH];
  100. HANDLE hfile;
  101. OBJECT_ATTRIBUTES ObjA;
  102. LARGE_INTEGER liOffset;
  103. ULONG uBytes;
  104. char szHeader[512];
  105. char szFormatHeader[] = "-------------------------------------------\r\n"
  106. " Log \"%S\" using ShimEngV\r\n"
  107. "-------------------------------------------\r\n";
  108. IO_STATUS_BLOCK ioStatusBlock;
  109. RtlInitUnicodeString(&EnvName, L"SHIM_FILE_LOG");
  110. EnvValue.Buffer = wszEnvValue;
  111. EnvValue.Length = 0;
  112. EnvValue.MaximumLength = sizeof(wszEnvValue);
  113. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  114. if (!NT_SUCCESS(status)) {
  115. DPF(("[SevInitFileLog] Logging not enabled\n"));
  116. return FALSE;
  117. }
  118. FilePath.Buffer = wszLogFile;
  119. FilePath.Length = 0;
  120. FilePath.MaximumLength = sizeof(wszLogFile);
  121. RtlInitUnicodeString(&NtSystemRoot, USER_SHARED_DATA->NtSystemRoot);
  122. RtlAppendUnicodeStringToString(&FilePath, &NtSystemRoot);
  123. RtlAppendUnicodeToString(&FilePath, L"\\AppPatch\\");
  124. RtlAppendUnicodeStringToString(&FilePath, &EnvValue);
  125. if (!RtlDosPathNameToNtPathName_U(FilePath.Buffer,
  126. &FilePath,
  127. NULL,
  128. NULL)) {
  129. DPF(("[SevInitFileLog] Failed to convert path name \"%S\"\n",
  130. wszLogFile));
  131. return FALSE;
  132. }
  133. InitializeObjectAttributes(&ObjA,
  134. &FilePath,
  135. OBJ_CASE_INSENSITIVE,
  136. NULL,
  137. NULL);
  138. //
  139. // Open/Create the log file
  140. //
  141. status = NtCreateFile(&hfile,
  142. FILE_APPEND_DATA | SYNCHRONIZE,
  143. &ObjA,
  144. &ioStatusBlock,
  145. NULL,
  146. FILE_ATTRIBUTE_NORMAL,
  147. 0,
  148. FILE_OPEN_IF,
  149. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  150. NULL,
  151. 0);
  152. RtlFreeUnicodeString(&FilePath);
  153. if (!NT_SUCCESS(status)) {
  154. DPF(("[SevInitFileLog] 0x%X Cannot open/create log file \"%S\"\n",
  155. status, wszLogFile));
  156. return FALSE;
  157. }
  158. //
  159. // Now write a new line in the log file
  160. //
  161. ioStatusBlock.Status = 0;
  162. ioStatusBlock.Information = 0;
  163. liOffset.LowPart = 0;
  164. liOffset.HighPart = 0;
  165. uBytes = (ULONG)sprintf(szHeader, szFormatHeader, pstrAppName->Buffer);
  166. status = NtWriteFile(hfile,
  167. NULL,
  168. NULL,
  169. NULL,
  170. &ioStatusBlock,
  171. (PVOID)szHeader,
  172. uBytes,
  173. &liOffset,
  174. NULL);
  175. NtClose(hfile);
  176. if (!NT_SUCCESS(status)) {
  177. DPF(("[SevInitFileLog] 0x%X Cannot write into the log file \"%S\"\n",
  178. status, wszLogFile));
  179. return FALSE;
  180. }
  181. return TRUE;
  182. }
  183. void
  184. SevSetLayerEnvVar(
  185. HSDB hSDB,
  186. TAGREF trLayer
  187. )
  188. {
  189. NTSTATUS status;
  190. UNICODE_STRING EnvName;
  191. UNICODE_STRING EnvValue;
  192. WCHAR wszEnvValue[128];
  193. PDB pdb;
  194. TAGID tiLayer, tiName;
  195. WCHAR* pwszName;
  196. RtlInitUnicodeString(&EnvName, L"__COMPAT_LAYER");
  197. EnvValue.Buffer = wszEnvValue;
  198. EnvValue.Length = 0;
  199. EnvValue.MaximumLength = sizeof(wszEnvValue);
  200. status = RtlQueryEnvironmentVariable_U(NULL, &EnvName, &EnvValue);
  201. if (NT_SUCCESS(status)) {
  202. DPF(("[SevSetLayerEnvVar] Env var set __COMPAT_LAYER=\"%S\"\n", wszEnvValue));
  203. return;
  204. }
  205. //
  206. // We need to set the environment variable
  207. //
  208. if (!SdbTagRefToTagID(hSDB, trLayer, &pdb, &tiLayer)) {
  209. DPF(("[SevSetLayerEnvVar] Failed to get tag id from tag ref\n"));
  210. return;
  211. }
  212. tiName = SdbFindFirstTag(pdb, tiLayer, TAG_NAME);
  213. if (tiName == TAGID_NULL) {
  214. DPF(("[SevSetLayerEnvVar] Failed to get the name tag id\n"));
  215. return;
  216. }
  217. pwszName = SdbGetStringTagPtr(pdb, tiName);
  218. if (pwszName == NULL) {
  219. DPF(("[SevSetLayerEnvVar] Cannot read the name of the layer tag\n"));
  220. return;
  221. }
  222. RtlInitUnicodeString(&EnvValue, pwszName);
  223. status = RtlSetEnvironmentVariable(NULL, &EnvName, &EnvValue);
  224. if (NT_SUCCESS(status)) {
  225. DPF(("[SevSetLayerEnvVar] Env var set __COMPAT_LAYER=\"%S\"\n", pwszName));
  226. } else {
  227. DPF(("[SevSetLayerEnvVar] Failed to set __COMPAT_LAYER. 0x%X\n", status));
  228. }
  229. }
  230. void
  231. SE_InstallBeforeInit(
  232. IN PUNICODE_STRING UnicodeImageName,
  233. IN PVOID pAppCompatExeData
  234. )
  235. /*++
  236. Routine Description:
  237. This function is called to install any api hooks, patches or flags for an exe.
  238. It's primary function is to initialize all the Shim data used in the hooking
  239. process.
  240. Arguments:
  241. UnicodeImageName - This is a Unicode string which contains the name of the exe to
  242. search for in the database.
  243. Return Value:
  244. Success if we are able to iterate through the patch data without error.
  245. Otherwise we return STATUS_UNSUCCESSFUL which indicates a more serious problem
  246. occured.
  247. --*/
  248. {
  249. UNICODE_STRING UnicodeString;
  250. ANSI_STRING AnsiString;
  251. ANSI_STRING ProcedureNameString;
  252. PVOID ModuleHandle = 0;
  253. PBYTE pAddress = 0;
  254. PBYTE pDLLBits = 0;
  255. PHOOKAPI *ppHooks = 0;
  256. PHOOKAPI *pHookArray = 0;
  257. PHOOKAPI pTemp = 0;
  258. DWORD dwHookCount = 0;
  259. DWORD dwHookIndex = 0;
  260. BOOL bResult = FALSE;
  261. NTSTATUS status;
  262. DWORD dwSize = 0;
  263. DWORD dwCounter = 0;
  264. PDWORD pdwNumberHooksArray = 0;
  265. PFNGETHOOKAPIS pfnGetHookApis = 0;
  266. DWORD dwTotalHooks = 0;
  267. DWORD dwDLLCount = 0;
  268. DWORD dwFuncAddress = 0;
  269. DWORD dwUnhookedCount = 0;
  270. TAGREF trExe = TAGREF_NULL;
  271. TAGREF trLayer = TAGREF_NULL;
  272. TAGREF trDllRef = TAGREF_NULL;
  273. TAGREF trKernelFlags = TAGREF_NULL;
  274. TAGREF trPatchRef = TAGREF_NULL;
  275. TAGREF trCmdLine = TAGREF_NULL;
  276. TAGREF trName = TAGREF_NULL;
  277. TAGREF trShimName = TAGREF_NULL;
  278. ULARGE_INTEGER likf;
  279. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  280. PPEB Peb;
  281. WCHAR wszDLLPath[MAX_PATH * 2];
  282. WCHAR wszShimName[MAX_PATH];
  283. WCHAR *pwszCmdLine = 0;
  284. CHAR *pszCmdLine = 0;
  285. BOOL bUsingExeRef = TRUE;
  286. HSDB hSDB = NULL;
  287. SDBQUERYRESULT sdbQuery;
  288. DWORD dwNumExes = 0;
  289. #ifdef DEBUG_SPEW
  290. SevInitDebugSupport();
  291. #endif // DEBUG_SPEW
  292. //
  293. // Peb->pShimData is zeroed during process initialization
  294. //
  295. Peb = NtCurrentPeb();
  296. //
  297. // Zero out the compat flags
  298. //
  299. RtlZeroMemory(&Peb->AppCompatFlags, sizeof(LARGE_INTEGER));
  300. //
  301. // Initialize our global function pointers.
  302. //
  303. // This is done because these functions may be hooked by a shim and we don't want to trip
  304. // over a shim hook internally. If one of these functions is hooked, these global pointers
  305. // will be overwritten with thunk addresses.
  306. //
  307. g_pfnLdrLoadDLL = LdrLoadDll;
  308. g_pfnLdrUnloadDLL = LdrUnloadDll;
  309. g_pfnRtlAllocateHeap = RtlAllocateHeap;
  310. g_pfnRtlFreeHeap = RtlFreeHeap;
  311. //
  312. // check whether we have anything to do
  313. //
  314. if (pAppCompatExeData == NULL) {
  315. DPF(("[SE_InstallBeforeInit] NULL pAppCompatExeData\n"));
  316. goto cleanup;
  317. }
  318. //
  319. // Set up our own shim heap
  320. //
  321. g_pShimHeap = RtlCreateHeap(HEAP_GROWABLE,
  322. 0, // location isn't important
  323. 64 * 1024, // 64k is the initial heap size
  324. 8 * 1024, // bring in an 1/8 of the reserved pages
  325. 0,
  326. 0);
  327. if (g_pShimHeap == NULL) {
  328. //
  329. // We didn't get our heap
  330. //
  331. DPF(("[SE_InstallBeforeInit] Can't create shim heap\n"));
  332. goto cleanup;
  333. }
  334. //
  335. // Open up the Database and see if there's any blob information about this Exe
  336. //
  337. hSDB = SdbInitDatabase(0, NULL);
  338. if (NULL == hSDB) {
  339. //
  340. // Return success even though the database failed to init.
  341. //
  342. DPF(("[SE_InstallBeforeInit] Can't open shim DB\n"));
  343. goto cleanup;
  344. }
  345. bResult = SdbUnpackAppCompatData(hSDB,
  346. UnicodeImageName->Buffer,
  347. pAppCompatExeData,
  348. &sdbQuery);
  349. if (!bResult) {
  350. //
  351. // Return success even though we didn't get the exe.
  352. // This way a corrupt database won't stop an application from running
  353. // The shim will not install itself.
  354. //
  355. DPF(("[SEv_InstallBeforeInit] bad appcompat data for \"%S\"\n",
  356. UnicodeImageName->Buffer));
  357. goto cleanup;
  358. }
  359. //
  360. // TBD - decide whether we're actually keeping this up to date, and if so, we should
  361. // put in support for multiple exes and layers.
  362. //
  363. for (dwNumExes = 0; dwNumExes < SDB_MAX_EXES; ++dwNumExes) {
  364. if (sdbQuery.atrExes[dwNumExes] == TAGREF_NULL) {
  365. break;
  366. }
  367. }
  368. if (dwNumExes) {
  369. trExe = sdbQuery.atrExes[dwNumExes - 1];
  370. }
  371. trLayer = sdbQuery.atrLayers[0];
  372. //
  373. // Debug spew for matching notification
  374. //
  375. DPF(("[SE_InstallBeforeInit] Matched entry: %S\n", UnicodeImageName->Buffer));
  376. //
  377. // Compute the number of shim DLLs we need to inject
  378. //
  379. dwDLLCount = 0;
  380. if (trExe != TAGREF_NULL) {
  381. trDllRef = SdbFindFirstTagRef(hSDB, trExe, TAG_SHIM_REF);
  382. while (trDllRef) {
  383. dwDLLCount++;
  384. trDllRef = SdbFindNextTagRef(hSDB, trExe, trDllRef);
  385. }
  386. }
  387. if (trLayer != TAGREF_NULL) {
  388. //
  389. // Set the layer environment variable if not set
  390. //
  391. SevSetLayerEnvVar(hSDB, trLayer);
  392. trDllRef = SdbFindFirstTagRef(hSDB, trLayer, TAG_SHIM_REF);
  393. while (trDllRef) {
  394. dwDLLCount++;
  395. trDllRef = SdbFindNextTagRef(hSDB, trLayer, trDllRef);
  396. }
  397. }
  398. //
  399. // See if there are any shim DLLs
  400. //
  401. if (dwDLLCount == 0) {
  402. DPF(("[SE_InstallBeforeInit] No shim DLLs. Look for memory patches\n"));
  403. goto MemPatches;
  404. }
  405. //
  406. // Allocate our PEB data
  407. //
  408. if (Peb->pShimData == NULL) {
  409. status = SevInitializeData((PAPP_COMPAT_SHIM_INFO*)&(Peb->pShimData));
  410. if (status != STATUS_SUCCESS) {
  411. DPF(("[SE_InstallBeforeInit] Can't initialize shim data.\n"));
  412. goto cleanup;
  413. }
  414. }
  415. //
  416. // Allocate a storage pointer for our hook information
  417. // Note: The + 1 below is for our global hooks
  418. //
  419. pHookArray = (PHOOKAPI*)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  420. HEAP_ZERO_MEMORY,
  421. sizeof(PHOOKAPI) * (dwDLLCount + 1));
  422. if (pHookArray == NULL) {
  423. DPF(("[SE_InstallBeforeInit] Failure allocating hook array\n"));
  424. goto cleanup;
  425. }
  426. pdwNumberHooksArray = (PDWORD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  427. HEAP_ZERO_MEMORY,
  428. sizeof(DWORD) * (dwDLLCount + 1));
  429. if (pdwNumberHooksArray == NULL) {
  430. DPF(("[SE_InstallBeforeInit] Failure allocating number hooks array\n"));
  431. goto cleanup;
  432. }
  433. dwCounter = 0;
  434. //
  435. // Setup the log file
  436. //
  437. SevInitFileLog(UnicodeImageName);
  438. if (trExe != TAGREF_NULL) {
  439. trDllRef = SdbFindFirstTagRef(hSDB, trExe, TAG_SHIM_REF);
  440. if (trDllRef == TAGREF_NULL) {
  441. bUsingExeRef = FALSE;
  442. }
  443. } else {
  444. bUsingExeRef = FALSE;
  445. }
  446. if (!bUsingExeRef) {
  447. trDllRef = SdbFindFirstTagRef(hSDB, trLayer, TAG_SHIM_REF);
  448. }
  449. while (trDllRef != TAGREF_NULL) {
  450. if (!SdbGetDllPath(hSDB, trDllRef, wszDLLPath)) {
  451. DPF(("[SE_InstallBeforeInit] Failed to get DLL Path\n"));
  452. goto cleanup;
  453. }
  454. RtlInitUnicodeString(&UnicodeString, wszDLLPath);
  455. //
  456. // Check if we already loaded this DLL
  457. //
  458. status = LdrGetDllHandle(NULL,
  459. NULL,
  460. &UnicodeString,
  461. &ModuleHandle);
  462. if (!NT_SUCCESS(status)) {
  463. status = LdrLoadDll(UNICODE_NULL, NULL, &UnicodeString, &ModuleHandle);
  464. if (!NT_SUCCESS(status)) {
  465. DPF(("[SE_InstallBeforeInit] Failed to load DLL \"%S\"\n", wszDLLPath));
  466. goto cleanup;
  467. }
  468. }
  469. //
  470. // Retrieve shim name
  471. //
  472. wszShimName[0] = 0;
  473. trShimName = SdbFindFirstTagRef(hSDB, trDllRef, TAG_NAME);
  474. if (trShimName == TAGREF_NULL) {
  475. DPF(("[SEi_InstallBeforeInit] Could not retrieve shim name from entry.\n"));
  476. goto cleanup;
  477. }
  478. if (!SdbReadStringTagRef(hSDB, trShimName, wszShimName, MAX_PATH)) {
  479. DPF(("[SEi_InstallBeforeInit] Could not retrieve shim name from entry.\n"));
  480. goto cleanup;
  481. }
  482. //
  483. // Check for command line
  484. //
  485. pwszCmdLine = (WCHAR*)(*g_pfnRtlAllocateHeap)(RtlProcessHeap(),
  486. HEAP_ZERO_MEMORY,
  487. SHIM_COMMAND_LINE_MAX_BUFFER * sizeof(WCHAR));
  488. if (pwszCmdLine == NULL) {
  489. DPF(("[SE_InstallBeforeInit] Failure allocating command line\n"));
  490. goto cleanup;
  491. }
  492. pszCmdLine = (CHAR*)(*g_pfnRtlAllocateHeap)(RtlProcessHeap(),
  493. HEAP_ZERO_MEMORY,
  494. SHIM_COMMAND_LINE_MAX_BUFFER * sizeof(CHAR));
  495. if (pszCmdLine == NULL) {
  496. DPF(("[SE_InstallBeforeInit] Failure allocating command line\n"));
  497. goto cleanup;
  498. }
  499. //
  500. // Default value
  501. //
  502. pszCmdLine[0] = '\0';
  503. trCmdLine = SdbFindFirstTagRef(hSDB, trDllRef, TAG_COMMAND_LINE);
  504. if (trCmdLine != TAGREF_NULL) {
  505. if (SdbReadStringTagRef(hSDB,
  506. trCmdLine,
  507. pwszCmdLine,
  508. SHIM_COMMAND_LINE_MAX_BUFFER)) {
  509. //
  510. // Convert command line to ANSI string
  511. //
  512. RtlInitUnicodeString(&UnicodeString, pwszCmdLine);
  513. RtlInitAnsiString(&AnsiString, pszCmdLine);
  514. AnsiString.MaximumLength = SHIM_COMMAND_LINE_MAX_BUFFER;
  515. status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  516. //
  517. // If conversion is unsuccessful, reset to zero-length string
  518. //
  519. if(!NT_SUCCESS(status)) {
  520. pszCmdLine[0] = '\0';
  521. }
  522. }
  523. }
  524. //
  525. // Get the GetHookApis entry point
  526. //
  527. RtlInitString(&ProcedureNameString, "GetHookAPIs");
  528. status = LdrGetProcedureAddress(ModuleHandle,
  529. &ProcedureNameString,
  530. 0,
  531. (PVOID*)&dwFuncAddress);
  532. if (!NT_SUCCESS(status)) {
  533. DPF(("[SE_InstallBeforeInit] Failed to get GetHookAPIs address, DLL \"%S\"\n",
  534. wszDLLPath));
  535. goto cleanup;
  536. }
  537. pfnGetHookApis = (PFNGETHOOKAPIS)dwFuncAddress;
  538. if (pfnGetHookApis == NULL) {
  539. DPF(("[SE_InstallBeforeInit] GetHookAPIs address NULL, DLL \"%S\"\n", wszDLLPath));
  540. goto cleanup;
  541. }
  542. //
  543. // Call the proc and then store away its hook params
  544. //
  545. pHookArray[dwCounter] = (*pfnGetHookApis)(pszCmdLine, wszShimName, &dwTotalHooks);
  546. if (pHookArray[dwCounter] == NULL) {
  547. //
  548. // Failed to get a hook set
  549. //
  550. DPF(("[SE_InstallBeforeInit] GetHookAPIs returns 0 hooks, DLL \"%S\"\n",
  551. wszDLLPath));
  552. pdwNumberHooksArray[dwCounter] = 0;
  553. } else {
  554. pdwNumberHooksArray[dwCounter] = dwTotalHooks;
  555. //
  556. // Set the DLL index number in the hook data
  557. //
  558. pTemp = pHookArray[dwCounter];
  559. for (dwHookIndex = 0; dwHookIndex < dwTotalHooks; dwHookIndex++) {
  560. //
  561. // Index information about the filter in maintained in the flags
  562. //
  563. pTemp[dwHookIndex].dwFlags = (WORD)dwCounter;
  564. }
  565. }
  566. dwCounter++;
  567. //
  568. // Get the next shim DLL ref
  569. //
  570. if (bUsingExeRef) {
  571. trDllRef = SdbFindNextTagRef(hSDB, trExe, trDllRef);
  572. if (trDllRef == TAGREF_NULL && trLayer != TAGREF_NULL) {
  573. bUsingExeRef = FALSE;
  574. trDllRef = SdbFindFirstTagRef(hSDB, trLayer, TAG_SHIM_REF);
  575. }
  576. } else {
  577. trDllRef = SdbFindNextTagRef(hSDB, trLayer, trDllRef);
  578. }
  579. }
  580. //
  581. // Build up our inclusion/exclusion filter
  582. //
  583. status = SevBuildExeFilter(hSDB, trExe, dwDLLCount);
  584. if (status != STATUS_SUCCESS) {
  585. //
  586. // Return success even though we didn't get the exe.
  587. // This way a corrupt database won't stop an application from running
  588. // The shim will not install itself.
  589. //
  590. DPF(("[SE_InstallBeforeInit] Unsuccessful building EXE filter, EXE \"%S\"\n",
  591. UnicodeImageName->Buffer));
  592. goto cleanup;
  593. }
  594. //
  595. // Add our LdrLoadDll hook to the fixup list
  596. //
  597. g_InternalHookArray[0].pszModule = "NTDLL.DLL";
  598. g_InternalHookArray[0].pszFunctionName = "LdrLoadDll";
  599. g_InternalHookArray[0].pfnNew = (PVOID)StubLdrLoadDll;
  600. g_InternalHookArray[0].pfnOld = NULL;
  601. g_InternalHookArray[1].pszModule = "NTDLL.DLL";
  602. g_InternalHookArray[1].pszFunctionName = "LdrUnloadDll";
  603. g_InternalHookArray[1].pfnNew = (PVOID)StubLdrUnloadDll;
  604. g_InternalHookArray[1].pfnOld = NULL;
  605. pHookArray[dwCounter] = g_InternalHookArray;
  606. pdwNumberHooksArray[dwCounter] = 2;
  607. //
  608. // Walk the hook list and fixup available procs
  609. //
  610. status = SevFixupAvailableProcs((dwCounter + 1),
  611. pHookArray,
  612. pdwNumberHooksArray,
  613. &dwUnhookedCount);
  614. if (status != STATUS_SUCCESS) {
  615. DPF(("[SE_InstallBeforeInit] Unsuccessful fixing up Procs, EXE \"%S\"\n",
  616. UnicodeImageName->Buffer));
  617. goto cleanup;
  618. }
  619. //
  620. // Compact the hook array for the unhooked funcs and hang it off the PEB
  621. //
  622. dwHookIndex = 0;
  623. ppHooks = 0;
  624. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  625. if (dwUnhookedCount) {
  626. ppHooks = (PHOOKAPI*)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  627. HEAP_ZERO_MEMORY,
  628. sizeof(PHOOKAPI) * dwUnhookedCount);
  629. if (ppHooks == NULL){
  630. DPF(("[SE_InstallBeforeInit] Unsuccessful allocating ppHooks, EXE \"%S\"\n",
  631. UnicodeImageName->Buffer));
  632. goto cleanup;
  633. }
  634. //
  635. // Iterate and copy the unhooked stuff
  636. //
  637. for (dwCounter = 0; dwCounter < dwDLLCount; dwCounter++) {
  638. for (dwHookCount = 0; dwHookCount < pdwNumberHooksArray[dwCounter]; dwHookCount++) {
  639. pTemp = pHookArray[dwCounter];
  640. if (pTemp && (0 == pTemp[dwHookCount].pfnOld)) {
  641. //
  642. // Wasn't hooked
  643. //
  644. ppHooks[dwHookIndex] = &pTemp[dwHookCount];
  645. dwHookIndex++;
  646. }
  647. }
  648. }
  649. //
  650. // Update the PEB with this flat unhooked data
  651. //
  652. pShimData->ppHookAPI = ppHooks;
  653. pShimData->dwHookAPICount = dwUnhookedCount;
  654. }
  655. //
  656. // Done with shim DLLs. Look for memory patches now.
  657. //
  658. MemPatches:
  659. if (trExe != TAGREF_NULL) {
  660. //
  661. // Walk the patch list and do the ops
  662. //
  663. trPatchRef = SdbFindFirstTagRef(hSDB, trExe, TAG_PATCH_REF);
  664. if (trPatchRef != TAGREF_NULL) {
  665. //
  666. // Initialize our PEB structure if we didn't get any API hooks
  667. //
  668. if (Peb->pShimData == NULL) {
  669. status = SevInitializeData((PAPP_COMPAT_SHIM_INFO*)&(Peb->pShimData));
  670. if (status != STATUS_SUCCESS) {
  671. DPF(("[SE_InstallBeforeInit] Unsuccessful initializing shim data, EXE \"%S\"\n",
  672. UnicodeImageName->Buffer));
  673. goto cleanup;
  674. }
  675. }
  676. while (trPatchRef != TAGREF_NULL) {
  677. //
  678. // Grab our patch blobs and get them hooked in for execution
  679. //
  680. dwSize = 0;
  681. SdbReadPatchBits(hSDB, trPatchRef, NULL, &dwSize);
  682. if (dwSize == 0) {
  683. DPF(("[SE_InstallBeforeInit] returned 0 for patch size, EXE \"%S\"\n",
  684. UnicodeImageName->Buffer));
  685. goto cleanup;
  686. }
  687. pAddress = (*g_pfnRtlAllocateHeap)(g_pShimHeap,
  688. HEAP_ZERO_MEMORY,
  689. dwSize);
  690. if (!SdbReadPatchBits(hSDB, trPatchRef, pAddress, &dwSize)) {
  691. DPF(("[SE_InstallBeforeInit] Failure getting patch bits, EXE \"%S\"\n",
  692. UnicodeImageName->Buffer));
  693. goto cleanup;
  694. }
  695. //
  696. // Do the initial operations
  697. //
  698. status = SevExecutePatchPrimitive(pAddress);
  699. if (status != STATUS_SUCCESS) {
  700. //
  701. // If the patch failed, ignore the error and continue trying additional patches
  702. //
  703. DPF(("[SE_InstallBeforeInit] Failure executing patch, EXE \"%S\"\n",
  704. UnicodeImageName->Buffer));
  705. }
  706. //
  707. // At this point the patch is hooked if necessary
  708. //
  709. trPatchRef = SdbFindNextTagRef(hSDB, trExe, trPatchRef);
  710. }
  711. }
  712. //
  713. // Set the flags for this exe in the PEB
  714. //
  715. ZeroMemory(&likf, sizeof(LARGE_INTEGER));
  716. trKernelFlags = SdbFindFirstTagRef(hSDB, trExe, TAG_FLAG_MASK_KERNEL);
  717. if (trKernelFlags != TAGREF_NULL) {
  718. likf.QuadPart = SdbReadQWORDTagRef(hSDB, trKernelFlags, 0);
  719. }
  720. if (likf.LowPart || likf.HighPart) {
  721. //
  722. // Initialize our PEB structure if we didn't get any API hooks or patches
  723. //
  724. if (Peb->pShimData == NULL) {
  725. status = SevInitializeData((PAPP_COMPAT_SHIM_INFO*)&(Peb->pShimData));
  726. if ( STATUS_SUCCESS != status ) {
  727. DPF(("[SE_InstallBeforeInit] Unsuccessful initializing shim data, EXE \"%S\"\n",
  728. UnicodeImageName->Buffer));
  729. goto cleanup;
  730. }
  731. }
  732. //
  733. // Store the flags in our kernel mode struct for access later
  734. //
  735. Peb->AppCompatFlags = likf;
  736. }
  737. }
  738. cleanup:
  739. //
  740. // Cleanup
  741. //
  742. if (pHookArray != NULL) {
  743. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pHookArray);
  744. }
  745. if (pdwNumberHooksArray != NULL) {
  746. (*g_pfnRtlFreeHeap)(g_pShimHeap, 0, pdwNumberHooksArray);
  747. }
  748. if (pszCmdLine != NULL) {
  749. (*g_pfnRtlFreeHeap)(RtlProcessHeap(), 0, pszCmdLine);
  750. }
  751. if (pwszCmdLine != NULL) {
  752. (*g_pfnRtlFreeHeap)(RtlProcessHeap(), 0, pwszCmdLine);
  753. }
  754. if (trExe != TAGREF_NULL) {
  755. SdbReleaseMatchingExe(hSDB, trExe);
  756. }
  757. if (pAppCompatExeData != NULL) {
  758. dwSize = SdbGetAppCompatDataSize(pAppCompatExeData);
  759. if (dwSize != 0) {
  760. NtFreeVirtualMemory(NtCurrentProcess(),
  761. &pAppCompatExeData,
  762. &dwSize,
  763. MEM_RELEASE);
  764. }
  765. }
  766. if (hSDB != NULL) {
  767. SdbReleaseDatabase(hSDB);
  768. }
  769. return;
  770. }
  771. void
  772. SE_InstallAfterInit(
  773. IN PUNICODE_STRING UnicodeImageName,
  774. IN PVOID pAppCompatExeData
  775. )
  776. {
  777. return;
  778. UNREFERENCED_PARAMETER(UnicodeImageName);
  779. UNREFERENCED_PARAMETER(pAppCompatExeData);
  780. }
  781. void
  782. SE_DllLoaded(
  783. PLDR_DATA_TABLE_ENTRY LdrEntry
  784. )
  785. {
  786. PAPP_COMPAT_SHIM_INFO pShimData;
  787. PHOOKPATCHINFO pPatchHookList;
  788. PPEB Peb = NtCurrentPeb();
  789. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  790. //
  791. // Call the shim patcher so we have a chance to modify any memory before
  792. // the initialize routine takes over
  793. //
  794. if (pShimData) {
  795. pPatchHookList = (PHOOKPATCHINFO)pShimData->pHookPatchList;
  796. RtlEnterCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  797. while (pPatchHookList) {
  798. //
  799. // See if this patch is hooked with a thunk
  800. //
  801. if (0 == pPatchHookList->dwHookAddress &&
  802. 0 == pPatchHookList->pThunkAddress) {
  803. //
  804. // Patch is for DLL load
  805. //
  806. SevExecutePatchPrimitive((PBYTE)pPatchHookList->pData);
  807. }
  808. pPatchHookList = pPatchHookList->pNextHook;
  809. }
  810. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  811. //
  812. // Potentially one of our exception DLLs got rebased. Re-validate our filter data
  813. //
  814. SevValidateGlobalFilter();
  815. }
  816. }
  817. void
  818. SE_DllUnloaded(
  819. PLDR_DATA_TABLE_ENTRY LdrEntry
  820. )
  821. {
  822. return;
  823. UNREFERENCED_PARAMETER(LdrEntry);
  824. }
  825. void
  826. SE_GetProcAddress(
  827. PVOID* pProcedureAddress
  828. )
  829. {
  830. return;
  831. }
  832. BOOL
  833. SE_IsShimDll(
  834. PVOID pDllBase
  835. )
  836. {
  837. return 0;
  838. }
  839. NTSTATUS
  840. SevBuildExeFilter(
  841. HSDB hSDB,
  842. TAGREF trExe,
  843. DWORD dwDLLCount)
  844. /*++
  845. Routine Description:
  846. This function is a shim internal use facility which builds an API filter list.
  847. Arguments:
  848. dwDLLCount - Count of the number of DLLs used in this shim
  849. pBlob0 - Pointer to the shim database blob 0
  850. pExeMatch - Pointer to the exe for which we're bulding a filter list
  851. Return Value:
  852. Return is STATUS_SUCCESS if the exception list is built successfully, or an error otherwise.
  853. --*/
  854. {
  855. NTSTATUS status = STATUS_SUCCESS;
  856. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  857. PMODULEFILTER *pDLLVector = 0;
  858. PMODULEFILTER pModFilter = 0;
  859. PMODULEFILTER pLastGlobal = 0;
  860. PMODULEFILTER pLast = 0;
  861. DWORD dwDLLIndex = 0;
  862. TAGREF trDatabase = TAGREF_NULL;
  863. TAGREF trLibrary = TAGREF_NULL;
  864. TAGREF trDll = TAGREF_NULL;
  865. TAGREF trDllRef = TAGREF_NULL;
  866. TAGREF trInclude = TAGREF_NULL;
  867. TAGREF trName = TAGREF_NULL;
  868. WCHAR wszDLLPath[MAX_PATH * 2];
  869. BOOL bLateBound = FALSE;
  870. pShimData = (PAPP_COMPAT_SHIM_INFO)NtCurrentPeb()->pShimData;
  871. if (0 == pShimData) {
  872. DPF(("[SevBuildExeFilter] Bad shim data.\n"));
  873. return STATUS_UNSUCCESSFUL;
  874. }
  875. if (0 == trExe) {
  876. DPF(("[SevBuildExeFilter] Bad trExe.\n"));
  877. return STATUS_UNSUCCESSFUL;
  878. }
  879. //
  880. // Allocate our DLL exception list vector
  881. //
  882. pShimData->pExeFilter = (PVOID)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  883. HEAP_ZERO_MEMORY,
  884. sizeof(PMODULEFILTER) * dwDLLCount);
  885. if (0 == pShimData->pExeFilter) {
  886. DPF(("[SevBuildExeFilter] Failure allocating Exe filter.\n"));
  887. return STATUS_UNSUCCESSFUL;
  888. }
  889. //
  890. // Walk the EXE DLL filter data (if any exists)
  891. //
  892. pDLLVector = (PMODULEFILTER *)pShimData->pExeFilter;
  893. trDllRef = SdbFindFirstTagRef(hSDB, trExe, TAG_SHIM_REF);
  894. dwDLLIndex = 0;
  895. while (trDllRef) {
  896. //
  897. // Grab the dll filter info and walk it
  898. //
  899. trInclude = SdbFindFirstTagRef(hSDB, trDllRef, TAG_INEXCLUDE);
  900. while (trInclude) {
  901. //
  902. // Allocate some memory for this filter
  903. //
  904. pModFilter = (PMODULEFILTER)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  905. HEAP_ZERO_MEMORY,
  906. sizeof(MODULEFILTER));
  907. if (0 == pModFilter) {
  908. DPF(("[SevBuildExeFilter] Failure allocating pModFilter.\n"));
  909. return STATUS_UNSUCCESSFUL;
  910. }
  911. status = SevBuildFilterException(hSDB,
  912. trInclude,
  913. pModFilter,
  914. &bLateBound);
  915. if (STATUS_SUCCESS != status) {
  916. DPF(("[SevBuildExeFilter] Failure SevBuildFilterException.\n"));
  917. return status;
  918. }
  919. //
  920. // Add entry to the list
  921. //
  922. if (0 == pDLLVector[dwDLLIndex]) {
  923. pDLLVector[dwDLLIndex] = pModFilter;
  924. } else if (pLast != NULL) {
  925. //
  926. // Add this to the tail end
  927. //
  928. pLast->pNextFilter = pModFilter;
  929. }
  930. pLast = pModFilter;
  931. //
  932. // See if we need to be in the late bound list
  933. //
  934. if (bLateBound) {
  935. pModFilter->pNextLBFilter = (PMODULEFILTER)pShimData->pLBFilterList;
  936. pShimData->pLBFilterList = (PVOID)pModFilter;
  937. }
  938. trInclude = SdbFindNextTagRef(hSDB, trDllRef, trInclude);
  939. }
  940. //
  941. // Add dll ref to the global exclusion filter
  942. //
  943. if (!SdbGetDllPath(hSDB, trDllRef, wszDLLPath)) {
  944. DPF(("[SevBuildExeFilter] Failure SdbGetDllPath.\n"));
  945. return status;
  946. }
  947. //
  948. // Allocate some memory for this filter
  949. //
  950. pModFilter = (PMODULEFILTER)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  951. HEAP_ZERO_MEMORY,
  952. sizeof(MODULEFILTER));
  953. if (0 == pModFilter) {
  954. DPF(("[SevBuildExeFilter] Failure allocating pModFilter.\n"));
  955. return STATUS_UNSUCCESSFUL;
  956. }
  957. status = SevAddShimFilterException(wszDLLPath,
  958. pModFilter);
  959. if (STATUS_SUCCESS != status) {
  960. //
  961. // If this happens its most likely a shim DLL wasn't loadable - this is fatal for the shim
  962. //
  963. DPF(("[SevBuildExeFilter] Failure SevAddShimFilterException.\n"));
  964. return status;
  965. }
  966. //
  967. // Add entry to the list
  968. //
  969. if (0 == pShimData->pGlobalFilterList) {
  970. pShimData->pGlobalFilterList = (PVOID)pModFilter;
  971. }
  972. else {
  973. //
  974. // Add this to the tail end
  975. //
  976. pLastGlobal->pNextFilter = pModFilter;
  977. }
  978. pLastGlobal = pModFilter;
  979. dwDLLIndex++;
  980. trDllRef = SdbFindNextTagRef(hSDB, trExe, trDllRef);
  981. }
  982. //
  983. // Walk the DLL filter data and add any additional exceptions to the EXE DLL list
  984. //
  985. trDllRef = SdbFindFirstTagRef(hSDB, trExe, TAG_SHIM_REF);
  986. dwDLLIndex = 0;
  987. while (trDllRef) {
  988. //
  989. // Lookup the EXE DLL in the DLL library
  990. //
  991. WCHAR wszName[MAX_PATH];
  992. trDll = SdbGetShimFromShimRef(hSDB, trDllRef);
  993. if (!trDll) {
  994. trDllRef = SdbFindNextTagRef(hSDB, trExe, trDllRef);
  995. continue;
  996. }
  997. wszName[0] = 0;
  998. trName = SdbFindFirstTagRef(hSDB, trDll, TAG_NAME);
  999. if (trName) {
  1000. SdbReadStringTagRef(hSDB, trName, wszName, MAX_PATH * sizeof(WCHAR));
  1001. }
  1002. //
  1003. // Debug spew for DLL injection notification
  1004. //
  1005. DPF(("[SevBuildExeFilter] Injected DLL: %S\n", wszName));
  1006. //
  1007. // Add these includes to the DLL exception list for this exe
  1008. //
  1009. trInclude = SdbFindFirstTagRef(hSDB, trDll, TAG_INEXCLUDE);
  1010. while(trInclude) {
  1011. //
  1012. // Allocate some memory for this filter
  1013. //
  1014. pModFilter = (PMODULEFILTER)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1015. HEAP_ZERO_MEMORY,
  1016. sizeof(MODULEFILTER));
  1017. if (0 == pModFilter) {
  1018. DPF(("[SevBuildExeFilter] Failure allocating pModFilter.\n"));
  1019. return STATUS_UNSUCCESSFUL;
  1020. }
  1021. status = SevBuildFilterException(hSDB,
  1022. trInclude,
  1023. pModFilter,
  1024. &bLateBound);
  1025. if (STATUS_SUCCESS != status) {
  1026. DPF(("[SevBuildExeFilter] Failure SevBuildFilterException.\n"));
  1027. return status;
  1028. }
  1029. //
  1030. // Add entry to the list
  1031. //
  1032. if (0 == pDLLVector[dwDLLIndex]) {
  1033. pDLLVector[dwDLLIndex] = pModFilter;
  1034. }
  1035. else {
  1036. //
  1037. // Add this to the tail end
  1038. //
  1039. pLast->pNextFilter = pModFilter;
  1040. }
  1041. pLast = pModFilter;
  1042. //
  1043. // See if we need to be in the late bound list
  1044. //
  1045. if (bLateBound) {
  1046. pModFilter->pNextLBFilter = (PMODULEFILTER)pShimData->pLBFilterList;
  1047. pShimData->pLBFilterList = (PVOID)pModFilter;
  1048. }
  1049. trInclude = SdbFindNextTagRef(hSDB, trDll, trInclude);
  1050. }
  1051. dwDLLIndex++;
  1052. trDllRef = SdbFindNextTagRef(hSDB, trExe, trDllRef);
  1053. }
  1054. //
  1055. // Walk the global exclusion data
  1056. //
  1057. //
  1058. // Set our list pointer to the last global exclusion added, if any
  1059. //
  1060. pLast = pLastGlobal;
  1061. trDatabase = SdbFindFirstTagRef(hSDB, TAGREF_ROOT, TAG_DATABASE);
  1062. if (!trDatabase) {
  1063. DPF(("[SevBuildExeFilter] Failure finding DATABASE.\n"));
  1064. goto cleanup;
  1065. }
  1066. trLibrary = SdbFindFirstTagRef(hSDB, trDatabase, TAG_LIBRARY);
  1067. if (!trLibrary) {
  1068. DPF(("[SevBuildExeFilter] Failure finding LIBRARY.\n"));
  1069. goto cleanup;
  1070. }
  1071. trInclude = SdbFindFirstTagRef(hSDB, trLibrary, TAG_INEXCLUDE);
  1072. while (trInclude) {
  1073. //
  1074. // Allocate some memory for this filter
  1075. //
  1076. pModFilter = (PMODULEFILTER)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1077. HEAP_ZERO_MEMORY,
  1078. sizeof(MODULEFILTER));
  1079. if (0 == pModFilter) {
  1080. DPF(("[SevBuildExeFilter] Failure allocating pModFilter.\n"));
  1081. return STATUS_UNSUCCESSFUL;
  1082. }
  1083. status = SevBuildFilterException(hSDB,
  1084. trInclude,
  1085. pModFilter,
  1086. &bLateBound);
  1087. if (STATUS_SUCCESS != status) {
  1088. DPF(("[SevBuildExeFilter] Failure SevBuildFilterException.\n"));
  1089. return status;
  1090. }
  1091. //
  1092. // Add entry to the list
  1093. //
  1094. if (0 == pShimData->pGlobalFilterList) {
  1095. pShimData->pGlobalFilterList = (PVOID)pModFilter;
  1096. }
  1097. else {
  1098. //
  1099. // Add this to the tail end
  1100. //
  1101. pLast->pNextFilter = pModFilter;
  1102. }
  1103. pLast = pModFilter;
  1104. //
  1105. // See if we need to be in the late bound list
  1106. //
  1107. if (bLateBound) {
  1108. pModFilter->pNextLBFilter = (PMODULEFILTER)pShimData->pLBFilterList;
  1109. pShimData->pLBFilterList = (PVOID)pModFilter;
  1110. }
  1111. trInclude = SdbFindNextTagRef(hSDB, trLibrary, trInclude);
  1112. }
  1113. cleanup:
  1114. return status;
  1115. }
  1116. NTSTATUS
  1117. SevBuildFilterException(
  1118. HSDB hSDB,
  1119. TAGREF trInclude,
  1120. PMODULEFILTER pModFilter,
  1121. BOOL* pbLateBound)
  1122. /*++
  1123. Routine Description:
  1124. This function is a shim internal use facility which builds an API filter.
  1125. Arguments:
  1126. trInclude - Tag ref from the database about the inclusion information to build
  1127. pModFilter - Filter structure to build used in the inclusion/exclusion filtering
  1128. pbLateBound - Boolean value which is set TRUE if a DLL needed to build the internal filter
  1129. wasn't present in the address space of the process.
  1130. Return Value:
  1131. Return is STATUS_SUCCESS if the exception is built successfully, or an error otherwise.
  1132. --*/
  1133. {
  1134. PVOID ModuleHandle = 0;
  1135. WCHAR *pwszDllName = 0;
  1136. UNICODE_STRING UnicodeString;
  1137. NTSTATUS status = STATUS_SUCCESS;
  1138. PIMAGE_NT_HEADERS NtHeaders = 0;
  1139. WCHAR wszModule[MAX_PATH];
  1140. DWORD dwModuleOffset = 0;
  1141. TAGREF trModule = TAGREF_NULL;
  1142. TAGREF trOffset = TAGREF_NULL;
  1143. *pbLateBound = FALSE;
  1144. //
  1145. // Mark this filter exception as inclusion/exclusion
  1146. //
  1147. if (SdbFindFirstTagRef(hSDB, trInclude, TAG_INCLUDE)) {
  1148. pModFilter->dwFlags |= MODFILTER_INCLUDE;
  1149. } else {
  1150. pModFilter->dwFlags |= MODFILTER_EXCLUDE;
  1151. }
  1152. //
  1153. // Convert addresses to absolute values and store
  1154. //
  1155. trModule = SdbFindFirstTagRef(hSDB, trInclude, TAG_MODULE);
  1156. if (!SdbReadStringTagRef(hSDB, trModule, wszModule, MAX_PATH * sizeof(WCHAR))) {
  1157. DPF(("[SevBuildFilterException] Failure reading module name.\n"));
  1158. return STATUS_UNSUCCESSFUL;
  1159. }
  1160. if ( L'*' == wszModule[0]) {
  1161. pModFilter->dwFlags |= MODFILTER_GLOBAL;
  1162. return status;
  1163. }
  1164. //
  1165. // Is this a global filter?
  1166. //
  1167. trOffset = SdbFindFirstTagRef(hSDB, trInclude, TAG_OFFSET);
  1168. if (trOffset) {
  1169. dwModuleOffset = SdbReadDWORDTagRef(hSDB, trOffset, 0);
  1170. }
  1171. if (0 == dwModuleOffset) {
  1172. pModFilter->dwFlags |= MODFILTER_DLL;
  1173. pModFilter->dwCallerOffset = dwModuleOffset;
  1174. }
  1175. if (L'$' == wszModule[0]) {
  1176. //
  1177. // Precalculate the caller address or call range
  1178. //
  1179. if (pModFilter->dwFlags & MODFILTER_DLL) {
  1180. //
  1181. // Set the address range
  1182. //
  1183. NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
  1184. pModFilter->dwModuleStart = (DWORD)NtCurrentPeb()->ImageBaseAddress;
  1185. pModFilter->dwModuleEnd = pModFilter->dwModuleStart + (DWORD)(NtHeaders->OptionalHeader.SizeOfImage);
  1186. }
  1187. else {
  1188. pModFilter->dwCallerAddress = (DWORD)NtCurrentPeb()->ImageBaseAddress + pModFilter->dwCallerOffset;
  1189. }
  1190. }
  1191. else {
  1192. RtlInitUnicodeString(&UnicodeString, wszModule);
  1193. //
  1194. // Make sure our module is loaded before calculating address ranges
  1195. //
  1196. status = LdrGetDllHandle(
  1197. NULL,
  1198. NULL,
  1199. &UnicodeString,
  1200. &ModuleHandle);
  1201. if (STATUS_SUCCESS != status) {
  1202. //
  1203. // We most likely have a late bound DLL which doesn't exist in the search path
  1204. //
  1205. *pbLateBound = TRUE;
  1206. pwszDllName = wszModule + wcslen(wszModule);
  1207. while(pwszDllName > wszModule) {
  1208. if ('\\' == *pwszDllName) {
  1209. break;
  1210. }
  1211. pwszDllName--;
  1212. }
  1213. //
  1214. // Check to see if we're at the beginning of the string or we hit a slash
  1215. //
  1216. if (pwszDllName > wszModule){
  1217. //
  1218. // Adjust our buffer pointer
  1219. //
  1220. pwszDllName++;
  1221. }
  1222. wcscpy(pModFilter->wszModuleName, pwszDllName);
  1223. return STATUS_SUCCESS;
  1224. }
  1225. //
  1226. // Precalculate the caller address or call range
  1227. //
  1228. if (pModFilter->dwFlags & MODFILTER_DLL) {
  1229. //
  1230. // Set the address range
  1231. //
  1232. NtHeaders = RtlImageNtHeader(ModuleHandle);
  1233. pModFilter->dwModuleStart = (DWORD)ModuleHandle;
  1234. pModFilter->dwModuleEnd = pModFilter->dwModuleStart + (DWORD)(NtHeaders->OptionalHeader.SizeOfImage);
  1235. }
  1236. else {
  1237. pModFilter->dwCallerAddress = (DWORD)ModuleHandle + pModFilter->dwCallerOffset;
  1238. }
  1239. }
  1240. //
  1241. // Copy just the DLL name
  1242. //
  1243. pwszDllName = wszModule + wcslen(wszModule);
  1244. while(pwszDllName > wszModule) {
  1245. if ('\\' == *pwszDllName) {
  1246. break;
  1247. }
  1248. pwszDllName--;
  1249. }
  1250. //
  1251. // Check to see if we're at the beginning of the string or we hit a slash
  1252. //
  1253. if (pwszDllName > wszModule){
  1254. //
  1255. // Adjust our buffer pointer
  1256. //
  1257. pwszDllName++;
  1258. }
  1259. wcscpy(pModFilter->wszModuleName, pwszDllName);
  1260. return status;
  1261. }
  1262. NTSTATUS
  1263. SevAddShimFilterException(WCHAR *wszDLLPath,
  1264. PMODULEFILTER pModFilter)
  1265. /*++
  1266. Routine Description:
  1267. This function is a shim internal use facility which builds an API filter.
  1268. Arguments:
  1269. wszDLLPath - Shim DLL which needs to be filtered
  1270. pModFilter - Pointer to a filter entry to build
  1271. Return Value:
  1272. Return is STATUS_SUCCESS if the exception is built successfully, or an error otherwise.
  1273. --*/
  1274. {
  1275. PVOID ModuleHandle = 0;
  1276. WCHAR *pwszDllName = 0;
  1277. UNICODE_STRING UnicodeString;
  1278. NTSTATUS status = STATUS_SUCCESS;
  1279. PIMAGE_NT_HEADERS NtHeaders = 0;
  1280. //
  1281. // Mark this exception as exclude
  1282. //
  1283. pModFilter->dwFlags |= MODFILTER_EXCLUDE;
  1284. //
  1285. // Shim exclusion re-entrancy is global
  1286. //
  1287. pModFilter->dwFlags |= MODFILTER_GLOBAL;
  1288. //
  1289. // The address filtering is by range
  1290. //
  1291. pModFilter->dwFlags |= MODFILTER_DLL;
  1292. //
  1293. // Load our DLL bits and get the mapping exclusion
  1294. //
  1295. RtlInitUnicodeString(&UnicodeString, wszDLLPath);
  1296. //
  1297. // Make sure our module is loaded before calculating address ranges
  1298. //
  1299. status = LdrGetDllHandle(
  1300. NULL,
  1301. NULL,
  1302. &UnicodeString,
  1303. &ModuleHandle);
  1304. if (STATUS_SUCCESS != status) {
  1305. //
  1306. // DLL wasn't loaded to do figure out the address mappings
  1307. //
  1308. DPF(("[SevAddShimFilterException] Failure LdrGetDllHandle.\n"));
  1309. return STATUS_UNSUCCESSFUL;
  1310. }
  1311. //
  1312. // Precalculate the caller address or call range
  1313. //
  1314. if (pModFilter->dwFlags & MODFILTER_DLL) {
  1315. //
  1316. // Set the address range
  1317. //
  1318. NtHeaders = RtlImageNtHeader(ModuleHandle);
  1319. pModFilter->dwModuleStart = (DWORD)ModuleHandle;
  1320. pModFilter->dwModuleEnd = pModFilter->dwModuleStart + (DWORD)(NtHeaders->OptionalHeader.SizeOfImage);
  1321. }
  1322. //
  1323. // Copy just the DLL name
  1324. //
  1325. pwszDllName = wszDLLPath + wcslen(wszDLLPath);
  1326. while(pwszDllName > wszDLLPath) {
  1327. if ('\\' == *pwszDllName) {
  1328. break;
  1329. }
  1330. pwszDllName--;
  1331. }
  1332. //
  1333. // Check to see if we're at the beginning of the string or we hit a slash
  1334. //
  1335. if (pwszDllName > wszDLLPath){
  1336. //
  1337. // Adjust our buffer pointer
  1338. //
  1339. pwszDllName++;
  1340. }
  1341. wcscpy(pModFilter->wszModuleName, pwszDllName);
  1342. return status;
  1343. }
  1344. NTSTATUS
  1345. SevFixupAvailableProcs(DWORD dwHookCount,
  1346. PHOOKAPI *pHookArray,
  1347. PDWORD pdwNumberHooksArray,
  1348. PDWORD pdwUnhookedCount)
  1349. /*++
  1350. Routine Description:
  1351. The primary function of this proc is to get any defined API hooks snapped in to place.
  1352. It has to build a call thunk and insert the hook mechanism into the API entry before any
  1353. function is hooked. An entry for the hooked function hangs off the PEB so the call can be
  1354. redirected when the function is executed.
  1355. Arguments:
  1356. dwHookCount - Number of hook blobs to walk
  1357. pHookArray - Pointer to the array of hook blobs
  1358. pdwNumberHooksArray - Pointer to a dword array which contains the hooks per blob
  1359. pdwUnhookedCount - Pointer to a dword which will contian the number of unhooked
  1360. functions on exit.
  1361. Return Value:
  1362. Return is STATUS_SUCCESS if no problems occured
  1363. --*/
  1364. {
  1365. ANSI_STRING AnsiString;
  1366. UNICODE_STRING UnicodeString;
  1367. WCHAR wBuffer[MAX_PATH*2];
  1368. DWORD dwCounter = 0;
  1369. DWORD dwApiCounter = 0;
  1370. PHOOKAPI pCurrentHooks = 0;
  1371. STRING ProcedureNameString;
  1372. PVOID ModuleHandle = 0;
  1373. DWORD dwFuncAddress = 0;
  1374. DWORD dwInstruction = 0;
  1375. NTSTATUS status = STATUS_SUCCESS;
  1376. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  1377. PVOID pThunk = 0;
  1378. DWORD dwThunkSize = 0;
  1379. PHOOKAPIINFO pTopHookAPIInfo = 0;
  1380. PHOOKAPI pCurrentHookTemp = 0;
  1381. PPEB Peb = 0;
  1382. BOOL bChained = FALSE;
  1383. PHOOKAPI pHookTemp = 0;
  1384. Peb = NtCurrentPeb();
  1385. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  1386. if (0 == dwHookCount || 0 == pHookArray) {
  1387. DPF(("[SevFixupAvailableProcs] Bad params.\n"));
  1388. return STATUS_UNSUCCESSFUL;
  1389. }
  1390. *pdwUnhookedCount = 0;
  1391. //
  1392. // Add any hooks which haven't already been entered
  1393. //
  1394. for (dwCounter = 0; dwCounter < dwHookCount; dwCounter++) {
  1395. //
  1396. // Iterate our array and search for the function to hook
  1397. //
  1398. pCurrentHooks = pHookArray[dwCounter];
  1399. if (0 == pCurrentHooks) {
  1400. //
  1401. // This was a hook which didn't initialize, skip over it
  1402. //
  1403. continue;
  1404. }
  1405. for (dwApiCounter = 0; dwApiCounter < pdwNumberHooksArray[dwCounter]; dwApiCounter++) {
  1406. //
  1407. // Is this DLL mapped in the address space?
  1408. //
  1409. RtlInitAnsiString(&AnsiString, pCurrentHooks[dwApiCounter].pszModule);
  1410. UnicodeString.Buffer = wBuffer;
  1411. UnicodeString.MaximumLength = sizeof(wBuffer);
  1412. if ( STATUS_SUCCESS != RtlAnsiStringToUnicodeString(&UnicodeString,
  1413. &AnsiString,
  1414. FALSE)){
  1415. DPF(("[SevFixupAvailableProcs] Failure LdrUnloadDll.\n"));
  1416. return STATUS_UNSUCCESSFUL;
  1417. }
  1418. status = LdrGetDllHandle(
  1419. NULL,
  1420. NULL,
  1421. &UnicodeString,
  1422. &ModuleHandle);
  1423. if (STATUS_SUCCESS != status) {
  1424. (*pdwUnhookedCount)++;
  1425. continue;
  1426. }
  1427. //
  1428. // Get the entry point for our hook
  1429. //
  1430. RtlInitString( &ProcedureNameString, pCurrentHooks[dwApiCounter].pszFunctionName );
  1431. status = LdrGetProcedureAddress(ModuleHandle,
  1432. &ProcedureNameString,
  1433. 0,
  1434. (PVOID *)&dwFuncAddress);
  1435. if ( STATUS_SUCCESS != status ) {
  1436. DPF(("[SevFixupAvailableProcs] Failure LdrGetProcedureAddress \"%s\".\n",
  1437. ProcedureNameString.Buffer));
  1438. return STATUS_UNSUCCESSFUL;
  1439. }
  1440. //
  1441. // Have we hooked this one already?
  1442. //
  1443. pTopHookAPIInfo = (PHOOKAPIINFO)pShimData->pHookAPIList;
  1444. bChained = FALSE;
  1445. //
  1446. // Keep the list locked while we iterate through it
  1447. //
  1448. RtlEnterCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1449. while (pTopHookAPIInfo) {
  1450. if (pTopHookAPIInfo->dwAPIHookAddress == dwFuncAddress) {
  1451. //
  1452. // We have already started an API hook chain
  1453. //
  1454. bChained = TRUE;
  1455. break;
  1456. }
  1457. pTopHookAPIInfo = pTopHookAPIInfo->pNextHook;
  1458. }
  1459. //
  1460. // Release our lock on the list
  1461. //
  1462. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1463. //
  1464. // We are chained - determine if this is a link we need to chain up
  1465. //
  1466. if (bChained) {
  1467. //
  1468. // Look at the chained flag and skip to the next API hook if already processed
  1469. //
  1470. if ((pCurrentHooks[dwApiCounter].dwFlags & HOOK_CHAINED) ||
  1471. (pCurrentHooks[dwApiCounter].dwFlags & HOOK_CHAIN_TOP)) {
  1472. //
  1473. // Already processed
  1474. //
  1475. continue;
  1476. }
  1477. }
  1478. //
  1479. // Insert the hook mechanism and build the call thunk
  1480. //
  1481. if (FALSE == bChained){
  1482. //
  1483. // Build the thunk for hooking this API
  1484. //
  1485. pThunk = SevBuildInjectionCode((PVOID)dwFuncAddress, &dwThunkSize);
  1486. if (!pThunk) {
  1487. DPF(("[SevFixupAvailableProcs] Failure allocating pThunk.\n"));
  1488. return STATUS_UNSUCCESSFUL;
  1489. }
  1490. //
  1491. // If we just created a call stub for a routine we're trying to step over
  1492. // fixup its thunk address now.
  1493. //
  1494. //
  1495. // We do this for LdrLoadDll...
  1496. //
  1497. if (0 == strcmp("LdrLoadDll",
  1498. pCurrentHooks[dwApiCounter].pszFunctionName)) {
  1499. g_pfnLdrLoadDLL = (PFNLDRLOADDLL)pThunk;
  1500. g_pfnOldLdrLoadDLL = (PFNLDRLOADDLL)dwFuncAddress;
  1501. }
  1502. //
  1503. // and LdrUnloadDLL ...
  1504. //
  1505. if (0 == strcmp("LdrUnloadDll",
  1506. pCurrentHooks[dwApiCounter].pszFunctionName)) {
  1507. g_pfnLdrUnloadDLL = (PFNLDRUNLOADDLL)pThunk;
  1508. g_pfnOldLdrUnloadDLL = (PFNLDRUNLOADDLL)dwFuncAddress;
  1509. }
  1510. //
  1511. // and RtlAllocateHeap ...
  1512. //
  1513. if (0 == strcmp("RtlAllocateHeap",
  1514. pCurrentHooks[dwApiCounter].pszFunctionName)) {
  1515. g_pfnRtlAllocateHeap = (PFNRTLALLOCATEHEAP)pThunk;
  1516. }
  1517. //
  1518. // and RtlFreeHeap ...
  1519. //
  1520. if (0 == strcmp("RtlFreeHeap",
  1521. pCurrentHooks[dwApiCounter].pszFunctionName)) {
  1522. g_pfnRtlFreeHeap = (PFNRTLFREEHEAP)pThunk;
  1523. }
  1524. //
  1525. // Mark the code to execute and get us into the entrypoint of our hooked function
  1526. //
  1527. status = SevFinishThunkInjection(dwFuncAddress,
  1528. pThunk,
  1529. dwThunkSize,
  1530. REASON_APIHOOK);
  1531. if (STATUS_SUCCESS != status) {
  1532. return status;
  1533. }
  1534. //
  1535. // Chain the newly created thunk to our hook list
  1536. //
  1537. status = SevChainAPIHook(dwFuncAddress,
  1538. pThunk,
  1539. &(pCurrentHooks[dwApiCounter]) );
  1540. if (STATUS_SUCCESS != status) {
  1541. DPF(("[SevFixupAvailableProcs] Failure on SevChainAPIHook.\n"));
  1542. return status;
  1543. }
  1544. //
  1545. // Set this as the top level hook
  1546. //
  1547. pCurrentHooks[dwApiCounter].dwFlags |= HOOK_CHAIN_TOP;
  1548. }
  1549. else {
  1550. //
  1551. // We are chaining APIs
  1552. //
  1553. //
  1554. // See if our old top-level hook has been chained up for the exception filter
  1555. //
  1556. if (0 == (pTopHookAPIInfo->pTopLevelAPIChain->dwFlags & HOOK_CHAINED)) {
  1557. //
  1558. // Add this one to the exception filter
  1559. //
  1560. //
  1561. // Build the thunk for hooking this API
  1562. //
  1563. pThunk = SevBuildInjectionCode(pTopHookAPIInfo->pTopLevelAPIChain->pfnNew,
  1564. &dwThunkSize);
  1565. if (!pThunk) {
  1566. DPF(("[SevFixupAvailableProcs] Failure allocating pThunk.\n"));
  1567. return STATUS_UNSUCCESSFUL;
  1568. }
  1569. //
  1570. // Mark the code to execute and get us into the entrypoint of our hooked function
  1571. //
  1572. status = SevFinishThunkInjection((DWORD)pTopHookAPIInfo->pTopLevelAPIChain->pfnNew,
  1573. pThunk,
  1574. dwThunkSize,
  1575. REASON_APIHOOK);
  1576. if (STATUS_SUCCESS != status) {
  1577. return status;
  1578. }
  1579. //
  1580. // Create a HOOKAPI shim entry for filtering this shim stub
  1581. //
  1582. pHookTemp = (PHOOKAPI)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1583. HEAP_ZERO_MEMORY,
  1584. sizeof(HOOKAPI));
  1585. if (!pHookTemp) {
  1586. DPF(("[SevFixupAvailableProcs] Failure allocating pHookTemp.\n"));
  1587. return STATUS_UNSUCCESSFUL;
  1588. }
  1589. //
  1590. // Add this to the end of the API chain list
  1591. //
  1592. pHookTemp->pfnOld = pTopHookAPIInfo->pTopLevelAPIChain->pfnOld;
  1593. pHookTemp->pfnNew = pThunk;
  1594. pHookTemp->dwFlags = (pTopHookAPIInfo->pTopLevelAPIChain->dwFlags & HOOK_INDEX_MASK);
  1595. pHookTemp->dwFlags |= HOOK_CHAINED;
  1596. pHookTemp->pszModule = pTopHookAPIInfo->pTopLevelAPIChain->pszModule;
  1597. //
  1598. // The call thunk below points to pfnOld which should skip us over this hook
  1599. // if its filtered
  1600. //
  1601. status = SevChainAPIHook((DWORD)pTopHookAPIInfo->pTopLevelAPIChain->pfnNew,
  1602. pThunk,
  1603. pHookTemp );
  1604. if (STATUS_SUCCESS != status) {
  1605. DPF(("[SevFixupAvailableProcs] Failure on SevChainAPIHook.\n"));
  1606. return status;
  1607. }
  1608. //
  1609. // Set this next hook pointer to NULL since it will always be the last link
  1610. //
  1611. pTopHookAPIInfo->pTopLevelAPIChain->pNextHook = 0;
  1612. //
  1613. // Clear the hooking flags so this isn't the top level chain
  1614. //
  1615. pTopHookAPIInfo->pTopLevelAPIChain->dwFlags &= HOOK_INDEX_MASK;
  1616. pTopHookAPIInfo->pTopLevelAPIChain->dwFlags |= HOOK_CHAINED;
  1617. }
  1618. else {
  1619. //
  1620. // Clear the hooking flags so this isn't the top level chain
  1621. //
  1622. pTopHookAPIInfo->pTopLevelAPIChain->dwFlags &= HOOK_INDEX_MASK;
  1623. pTopHookAPIInfo->pTopLevelAPIChain->dwFlags |= HOOK_CHAINED;
  1624. }
  1625. //
  1626. // New hook needs to be in the filtering list now
  1627. //
  1628. if (0 == (pCurrentHooks[dwApiCounter].dwFlags & HOOK_CHAINED)) {
  1629. //
  1630. // Add this one to the exception filter
  1631. //
  1632. //
  1633. // Build the thunk for hooking this API
  1634. //
  1635. pThunk = SevBuildInjectionCode(pCurrentHooks[dwApiCounter].pfnNew,
  1636. &dwThunkSize);
  1637. if (!pThunk) {
  1638. DPF(("[SevFixupAvailableProcs] Failure allocating pThunk.\n"));
  1639. return STATUS_UNSUCCESSFUL;
  1640. }
  1641. //
  1642. // Mark the code to execute and get us into the entrypoint of our hooked function
  1643. //
  1644. status = SevFinishThunkInjection((DWORD)pCurrentHooks[dwApiCounter].pfnNew,
  1645. pThunk,
  1646. dwThunkSize,
  1647. REASON_APIHOOK);
  1648. if (STATUS_SUCCESS != status) {
  1649. return status;
  1650. }
  1651. //
  1652. // Create a HOOKAPI shim entry for filtering this shim stub
  1653. //
  1654. pHookTemp = (PHOOKAPI)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1655. HEAP_ZERO_MEMORY,
  1656. sizeof(HOOKAPI));
  1657. if (!pHookTemp) {
  1658. DPF(("[SevFixupAvailableProcs] Failure allocating pHookTemp.\n"));
  1659. return STATUS_UNSUCCESSFUL;
  1660. }
  1661. //
  1662. // Insert our shim hook filter
  1663. //
  1664. pHookTemp->pfnOld = pCurrentHooks[dwApiCounter].pfnOld;
  1665. pHookTemp->pfnNew = pThunk;
  1666. pHookTemp->dwFlags = (pCurrentHooks[dwApiCounter].dwFlags & HOOK_INDEX_MASK);
  1667. pHookTemp->dwFlags |= HOOK_CHAINED;
  1668. pHookTemp->pszModule = pCurrentHooks[dwApiCounter].pszModule;
  1669. //
  1670. // The call thunk below points to pfnOld which should skip us over this hook
  1671. // if its filtered
  1672. //
  1673. status = SevChainAPIHook((DWORD)pCurrentHooks[dwApiCounter].pfnNew,
  1674. pThunk,
  1675. pHookTemp );
  1676. if (STATUS_SUCCESS != status) {
  1677. DPF(("[SevFixupAvailableProcs] Failure on SevChainAPIHook.\n"));
  1678. return status;
  1679. }
  1680. //
  1681. // Set the hook flags so this is the top level chain
  1682. //
  1683. pCurrentHooks[dwApiCounter].dwFlags &= HOOK_INDEX_MASK;
  1684. pCurrentHooks[dwApiCounter].dwFlags |= HOOK_CHAINED;
  1685. pCurrentHooks[dwApiCounter].dwFlags |= HOOK_CHAIN_TOP;
  1686. }
  1687. //
  1688. // API chain list needs to be updated so the new hook is the top and points toward
  1689. // our previous hook
  1690. //
  1691. pCurrentHooks[dwApiCounter].pNextHook = pTopHookAPIInfo->pTopLevelAPIChain;
  1692. //
  1693. // New hook needs to call the previous stub routine as the original
  1694. //
  1695. pCurrentHooks[dwApiCounter].pfnOld = pTopHookAPIInfo->pTopLevelAPIChain->pfnNew;
  1696. //
  1697. // In the shim PEB data, make this stub the top level handler on exception
  1698. //
  1699. pTopHookAPIInfo->pTopLevelAPIChain = &(pCurrentHooks[dwApiCounter]);
  1700. }
  1701. }
  1702. }
  1703. return STATUS_SUCCESS;
  1704. }
  1705. NTSTATUS
  1706. SevChainAPIHook (
  1707. DWORD dwHookEntryPoint,
  1708. PVOID pThunk,
  1709. PHOOKAPI pAPIHook
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. This routine adds a shimmed API to the internal API hook list.
  1714. Arguments:
  1715. dwHookEntryPoint - API entrypoint for which this hook exists
  1716. pThunk - Address of the code to execute to walk around a shim's hook
  1717. pAPIHook - Pointer to the HOOKAPI for this API hook
  1718. Return Value:
  1719. Return is STATUS_SUCCESS if no errors occured.
  1720. --*/
  1721. {
  1722. ANSI_STRING AnsiString;
  1723. UNICODE_STRING UnicodeString;
  1724. PHOOKAPIINFO pTempHookAPIInfo = 0;
  1725. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  1726. WCHAR wBuffer[MAX_PATH*2];
  1727. PPEB Peb = 0;
  1728. Peb = NtCurrentPeb();
  1729. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  1730. //
  1731. // Allocate some memory for this hook
  1732. //
  1733. pTempHookAPIInfo = (PHOOKAPIINFO)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1734. HEAP_ZERO_MEMORY,
  1735. sizeof(HOOKAPIINFO));
  1736. if (!pTempHookAPIInfo) {
  1737. DPF(("[SevChainAPIHook] Failure allocating pAPIHooks.\n"));
  1738. return STATUS_UNSUCCESSFUL;
  1739. }
  1740. DPF(("[SevChainAPIHook] Hooking \"%s!%s\".\n",
  1741. pAPIHook->pszModule,
  1742. pAPIHook->pszFunctionName));
  1743. pTempHookAPIInfo->pPrevHook = 0;
  1744. pTempHookAPIInfo->pNextHook = 0;
  1745. pTempHookAPIInfo->dwAPIHookAddress = dwHookEntryPoint;
  1746. pTempHookAPIInfo->pTopLevelAPIChain = pAPIHook;
  1747. pTempHookAPIInfo->pCallThunkAddress = pThunk;
  1748. pAPIHook->pfnOld = pThunk;
  1749. //
  1750. // Convert our module name over to a Unicode string (shim chain filter doesn't have a set module)
  1751. //
  1752. if (pAPIHook->pszModule) {
  1753. RtlInitAnsiString(&AnsiString, pAPIHook->pszModule);
  1754. UnicodeString.Buffer = wBuffer;
  1755. UnicodeString.MaximumLength = sizeof(wBuffer);
  1756. if ( STATUS_SUCCESS != RtlAnsiStringToUnicodeString(&UnicodeString,
  1757. &AnsiString,
  1758. FALSE)){
  1759. DPF(("[SevChainAPIHook] Failure RtlAnsiStringToUnicodeString.\n"));
  1760. return STATUS_UNSUCCESSFUL;
  1761. }
  1762. wcscpy(pTempHookAPIInfo->wszModuleName, UnicodeString.Buffer);
  1763. }
  1764. //
  1765. // Add to our hook list
  1766. //
  1767. //
  1768. // Prev points to head of list
  1769. //
  1770. pTempHookAPIInfo->pNextHook = pShimData->pHookAPIList;
  1771. pShimData->pHookAPIList = (PVOID)pTempHookAPIInfo;
  1772. if (pTempHookAPIInfo->pNextHook) {
  1773. pTempHookAPIInfo->pNextHook->pPrevHook = pTempHookAPIInfo;
  1774. }
  1775. return STATUS_SUCCESS;
  1776. }
  1777. LONG
  1778. SevExceptionHandler (
  1779. struct _EXCEPTION_POINTERS *ExceptionInfo
  1780. )
  1781. /*++
  1782. Routine Description:
  1783. This is where we trap all calls to "shimmed" APIs and patch hooks. Here is where you would want to also
  1784. want to handle any special priv mode instruction faults or any other exception type.
  1785. Arguments:
  1786. ExceptionInfo - Pointer to the exception information
  1787. Return Value:
  1788. Return is either EXCEPTION_CONTINUE_EXECUTION if we handled the exception, or
  1789. EXCEPTION_CONTINUE_SEARCH if we didn't.
  1790. --*/
  1791. {
  1792. PEXCEPTION_RECORD pExceptionRecord = 0;
  1793. PCONTEXT pContextRecord = 0;
  1794. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  1795. PHOOKAPIINFO pAPIHookList = 0;
  1796. PHOOKPATCHINFO pPatchHookList = 0;
  1797. PCHAININFO pTopChainInfo = 0;
  1798. PBYTE pjReason = 0;
  1799. PVOID pAddress = 0;
  1800. DWORD dwFilterIndex = 0;
  1801. PVOID pAPI = 0;
  1802. PVOID pCaller = 0;
  1803. PMODULEFILTER *pDLLVector = 0;
  1804. NTSTATUS status;
  1805. PPEB Peb = 0;
  1806. PTEB Teb = 0;
  1807. Peb = NtCurrentPeb();
  1808. Teb = NtCurrentTeb();
  1809. pShimData = Peb->pShimData;
  1810. pExceptionRecord = ExceptionInfo->ExceptionRecord;
  1811. pContextRecord = ExceptionInfo->ContextRecord;
  1812. //
  1813. // Handle any expected exception
  1814. //
  1815. switch(pExceptionRecord->ExceptionCode)
  1816. {
  1817. case STATUS_PRIVILEGED_INSTRUCTION:
  1818. //
  1819. // Move us to the reason for the exception
  1820. //
  1821. pjReason = (BYTE *)pExceptionRecord->ExceptionAddress;
  1822. switch(*pjReason)
  1823. {
  1824. case REASON_APIHOOK:
  1825. //
  1826. // Walk the APIHooks and then change our EIP
  1827. //
  1828. RtlEnterCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1829. pAPIHookList = (PHOOKAPIINFO)pShimData->pHookAPIList;
  1830. while(pAPIHookList) {
  1831. //
  1832. // Is this our hooked function?
  1833. //
  1834. if ((DWORD)pExceptionRecord->ExceptionAddress == pAPIHookList->dwAPIHookAddress) {
  1835. //
  1836. // Push on our caller on this thread if this is a top level hook
  1837. //
  1838. if (pAPIHookList->pTopLevelAPIChain->dwFlags & HOOK_CHAIN_TOP) {
  1839. //
  1840. // Push our caller onto the shim call stack for this thread
  1841. //
  1842. //
  1843. // Note the + 1 is due to the fact the original call pushed another ret address on the stack
  1844. //
  1845. status = SevPushCaller(pExceptionRecord->ExceptionAddress,
  1846. (PVOID)(*(DWORD *)pContextRecord->Esp));
  1847. if (STATUS_SUCCESS != status) {
  1848. //
  1849. // This shouldn't fail but if it does ...
  1850. //
  1851. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1852. //
  1853. // Try and give them the original function call to execute on failure
  1854. //
  1855. pContextRecord->Eip = (DWORD)pAPIHookList->pTopLevelAPIChain->pfnOld;
  1856. return EXCEPTION_CONTINUE_EXECUTION;
  1857. }
  1858. //
  1859. // Change the ret address so the original call can pop its shim data for the chain
  1860. //
  1861. *(DWORD *)pContextRecord->Esp = (DWORD)fnHandleRet;
  1862. }
  1863. //
  1864. // Filter our calling module
  1865. //
  1866. pTopChainInfo = (PCHAININFO)Teb->pShimData;
  1867. pAPI = pTopChainInfo->pAPI;
  1868. pCaller = pTopChainInfo->pReturn;
  1869. //
  1870. // Retrieve the exe filter for this shim module
  1871. //
  1872. dwFilterIndex = pAPIHookList->pTopLevelAPIChain->dwFlags & HOOK_INDEX_MASK;
  1873. pDLLVector = (PMODULEFILTER *)pShimData->pExeFilter;
  1874. pAddress = SevFilterCaller(pDLLVector[dwFilterIndex],
  1875. pAPI,
  1876. pCaller,
  1877. pAPIHookList->pTopLevelAPIChain->pfnNew,
  1878. pAPIHookList->pTopLevelAPIChain->pfnOld);
  1879. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1880. //
  1881. // Update our EIP to our pfnNew or PfnOld to continue
  1882. //
  1883. pContextRecord->Eip = (DWORD)pAddress;
  1884. return EXCEPTION_CONTINUE_EXECUTION;
  1885. }
  1886. pAPIHookList = pAPIHookList->pNextHook;
  1887. }
  1888. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1889. //
  1890. // REASON_APIHOOK wasn't one generated by us
  1891. //
  1892. break;
  1893. case REASON_PATCHHOOK:
  1894. //
  1895. // Find our patch, do next patch opcode
  1896. //
  1897. pPatchHookList = (PHOOKPATCHINFO)pShimData->pHookPatchList;
  1898. RtlEnterCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1899. while(pPatchHookList) {
  1900. //
  1901. // Is this our hooked function?
  1902. //
  1903. if ((DWORD)pExceptionRecord->ExceptionAddress == pPatchHookList->dwHookAddress){
  1904. //
  1905. // Execute the shim patch
  1906. //
  1907. status = SevExecutePatchPrimitive((PBYTE)((DWORD)pPatchHookList->pData + sizeof(SETACTIVATEADDRESS)));
  1908. if ( STATUS_SUCCESS != status ) {
  1909. //
  1910. // Patch failed to apply, silently abort it
  1911. //
  1912. DPF(("[SevExceptionHandler] Failed to execute patch.\n"));
  1913. }
  1914. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1915. //
  1916. // Jump around the patch hook
  1917. //
  1918. pContextRecord->Eip = (DWORD)pPatchHookList->pThunkAddress;
  1919. return EXCEPTION_CONTINUE_EXECUTION;
  1920. }
  1921. pPatchHookList = pPatchHookList->pNextHook;
  1922. }
  1923. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  1924. //
  1925. // REASON_PATCHHOOK wasn't one generated by us
  1926. //
  1927. break;
  1928. default:
  1929. //
  1930. // Wasn't a priv mode fault we expected
  1931. //
  1932. 0;
  1933. }
  1934. //
  1935. // Fall out for the not handled case for priv mode faults
  1936. //
  1937. break;
  1938. default:
  1939. 0;
  1940. }
  1941. //
  1942. // Not handled
  1943. //
  1944. return EXCEPTION_CONTINUE_SEARCH;
  1945. }
  1946. NTSTATUS
  1947. SevPushCaller (PVOID pAPIAddress,
  1948. PVOID pReturnAddress)
  1949. /*++
  1950. Routine Description:
  1951. This function pushes a top level shim onto the thread call stack to maintain caller
  1952. across hooks.
  1953. Arguments:
  1954. pAPIAddress - Pointer to the entry point of the API
  1955. pReturnAddress - Return address of the caller
  1956. Return Value:
  1957. Return is STATUS_SUCCESS if no problem occured
  1958. --*/
  1959. {
  1960. PCHAININFO pChainInfo = 0;
  1961. PCHAININFO pTopChainInfo = 0;
  1962. PTEB Teb = 0;
  1963. Teb = NtCurrentTeb();
  1964. pTopChainInfo = (PCHAININFO)Teb->pShimData;
  1965. pChainInfo = (PCHAININFO)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  1966. HEAP_ZERO_MEMORY,
  1967. sizeof(CHAININFO));
  1968. if (0 == pChainInfo){
  1969. DPF(("[SevPushCaller] Failure allocating pChainInfo.\n"));
  1970. return STATUS_UNSUCCESSFUL;
  1971. }
  1972. //
  1973. // Fill the chain data
  1974. //
  1975. pChainInfo->pAPI = pAPIAddress;
  1976. pChainInfo->pReturn = pReturnAddress;
  1977. //
  1978. // Add ourselves to the top of the chain
  1979. //
  1980. pChainInfo->pNextChain = pTopChainInfo;
  1981. Teb->pShimData = (PVOID)pChainInfo;
  1982. return STATUS_SUCCESS;
  1983. }
  1984. PVOID
  1985. SevPopCaller(VOID)
  1986. /*++
  1987. Routine Description:
  1988. This function pops a top level shim off of the thread call stack to maintain caller
  1989. across hooks.
  1990. Arguments:
  1991. None.
  1992. Return Value:
  1993. None.
  1994. --*/
  1995. {
  1996. PCHAININFO pTemp = 0;
  1997. PCHAININFO pTopChainInfo = 0;
  1998. PTEB Teb = 0;
  1999. PVOID pReturnAddress = 0;
  2000. Teb = NtCurrentTeb();
  2001. pTopChainInfo = (PCHAININFO)Teb->pShimData;
  2002. pReturnAddress = pTopChainInfo->pReturn;
  2003. pTemp = pTopChainInfo->pNextChain;
  2004. //
  2005. // Pop the caller
  2006. //
  2007. Teb->pShimData = (PVOID)pTemp;
  2008. //
  2009. // Free our allocation
  2010. //
  2011. (*g_pfnRtlFreeHeap)(g_pShimHeap,
  2012. 0,
  2013. pTopChainInfo);
  2014. return pReturnAddress;
  2015. }
  2016. NTSTATUS
  2017. SevInitializeData (PAPP_COMPAT_SHIM_INFO *pShimData)
  2018. /*++
  2019. Routine Description:
  2020. The primary function of the routine is to initialize the Shim data which hangs off the PEB
  2021. such that later we can chain our API hooks and/or patches.
  2022. Arguments:
  2023. pShimData - Pointer to our PEB data pointer for the shim
  2024. Return Value:
  2025. Return is STATUS_SUCCESS if no problem occured
  2026. --*/
  2027. {
  2028. //
  2029. // Allocate our PEB data
  2030. //
  2031. *pShimData = (PAPP_COMPAT_SHIM_INFO)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  2032. HEAP_ZERO_MEMORY,
  2033. sizeof(APP_COMPAT_SHIM_INFO));
  2034. if (0 == *pShimData){
  2035. DPF(("[SevExceptionHandler] Failure allocating pShimData.\n"));
  2036. return STATUS_UNSUCCESSFUL;
  2037. }
  2038. //
  2039. // Initialize our critical section
  2040. //
  2041. (*pShimData)->pCritSec = (PVOID)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  2042. HEAP_ZERO_MEMORY,
  2043. sizeof(CRITICAL_SECTION));
  2044. if (0 == (*pShimData)->pCritSec){
  2045. DPF(("[SevExceptionHandler] Failure allocating (*pShimData)->pCritSec.\n"));
  2046. return STATUS_UNSUCCESSFUL;
  2047. }
  2048. RtlInitializeCriticalSection((*pShimData)->pCritSec);
  2049. //
  2050. // Add ourselves to the exception filtering chain
  2051. //
  2052. if (0 == RtlAddVectoredExceptionHandler(1,
  2053. SevExceptionHandler)) {
  2054. DPF(("[SevExceptionHandler] Failure chaining exception handler.\n"));
  2055. return STATUS_UNSUCCESSFUL;
  2056. }
  2057. //
  2058. // Store away our shim heap pointer
  2059. //
  2060. (*pShimData)->pShimHeap = g_pShimHeap;
  2061. //
  2062. // Initialize the call thunks
  2063. //
  2064. dwCallArray[0] = (DWORD)SevPopCaller;
  2065. //
  2066. // We return through this code stub to unchain the shim call stack
  2067. //
  2068. fnHandleRet->PUSHEAX = 0x50; //push eax (50)
  2069. fnHandleRet->PUSHAD = 0x60; //pushad (60)
  2070. fnHandleRet->CALLROUTINE[0] = 0xff; //call [address] (ff15 dword address)
  2071. fnHandleRet->CALLROUTINE[1] = 0x15;
  2072. *(DWORD *)(&(fnHandleRet->CALLROUTINE[2])) = (DWORD)&dwCallArray[0];
  2073. fnHandleRet->MOVESPPLUS20EAX[0] = 0x89; //mov [esp+0x20],eax (89 44 24 20)
  2074. fnHandleRet->MOVESPPLUS20EAX[1] = 0x44;
  2075. fnHandleRet->MOVESPPLUS20EAX[2] = 0x24;
  2076. fnHandleRet->MOVESPPLUS20EAX[3] = 0x20;
  2077. fnHandleRet->POPAD = 0x61; //popad (61)
  2078. fnHandleRet->RET = 0xc3; //ret (c3)
  2079. return STATUS_SUCCESS;
  2080. }
  2081. NTSTATUS
  2082. SevExecutePatchPrimitive(PBYTE pPatch)
  2083. /*++
  2084. Routine Description:
  2085. This is the workhorse for the dynamic patching system. An opcode/data primitive is passed
  2086. through and the operation is completed in this routine if possible.
  2087. Arguments:
  2088. pPatch - Pointer to a data primitive to execute
  2089. Return Value:
  2090. Return is STATUS_SUCCESS if no problem occured
  2091. --*/
  2092. {
  2093. PPATCHMATCHDATA pMatchData = 0;
  2094. PPATCHWRITEDATA pWriteData = 0;
  2095. PSETACTIVATEADDRESS pActivateData = 0;
  2096. PPATCHOP pPatchOP = 0;
  2097. PHOOKPATCHINFO pPatchInfo = 0;
  2098. NTSTATUS status = STATUS_SUCCESS;
  2099. DWORD dwAddress = 0;
  2100. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  2101. PHOOKPATCHINFO pPatchHookList = 0;
  2102. PHOOKPATCHINFO pTempList = 0;
  2103. PVOID pThunk = 0;
  2104. DWORD dwInstruction = 0;
  2105. DWORD dwThunkSize = 0;
  2106. DWORD dwProtectSize = 0;
  2107. DWORD dwProtectFuncAddress = 0;
  2108. DWORD dwOldFlags = 0;
  2109. BOOL bIteratePatch = TRUE;
  2110. BOOL bInsertPatch = FALSE;
  2111. PPEB Peb;
  2112. Peb = NtCurrentPeb();
  2113. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  2114. //
  2115. // Grab the opcode and see what we have to do
  2116. //
  2117. while (bIteratePatch) {
  2118. pPatchOP = (PPATCHOP)pPatch;
  2119. switch(pPatchOP->dwOpcode)
  2120. {
  2121. case PEND:
  2122. //
  2123. // We are done, do nothing and return success
  2124. //
  2125. bIteratePatch = FALSE;
  2126. break;
  2127. case PSAA:
  2128. //
  2129. // This is a patch set application activate primitive - set it up
  2130. //
  2131. pActivateData = (PSETACTIVATEADDRESS)pPatchOP->data;
  2132. //
  2133. // Grab the physical address to do this operation
  2134. //
  2135. dwAddress = SevGetPatchAddress(&(pActivateData->rva));
  2136. if (0 == dwAddress && (0 != pActivateData->rva.address)) {
  2137. DPF(("[SevExecutePatchPrimitive] Failure SevGetPatchAddress.\n"));
  2138. return STATUS_UNSUCCESSFUL;
  2139. }
  2140. //
  2141. // See if we need a call thunk
  2142. //
  2143. if (0 != pActivateData->rva.address) {
  2144. //
  2145. // Build the thunk
  2146. //
  2147. pThunk = SevBuildInjectionCode((PVOID)dwAddress, &dwThunkSize);
  2148. if (!pThunk) {
  2149. DPF(("[SevExecutePatchPrimitive] Failure allocating pThunk.\n"));
  2150. return STATUS_UNSUCCESSFUL;
  2151. }
  2152. //
  2153. // Mark the code to execute and get us into the entrypoint of our hooked data
  2154. //
  2155. status = SevFinishThunkInjection(dwAddress,
  2156. pThunk,
  2157. dwThunkSize,
  2158. REASON_PATCHHOOK);
  2159. if (STATUS_SUCCESS != status) {
  2160. return status;
  2161. }
  2162. }
  2163. //
  2164. // Add ourselves to the hooked list
  2165. //
  2166. pPatchInfo = (*g_pfnRtlAllocateHeap)(g_pShimHeap,
  2167. HEAP_ZERO_MEMORY,
  2168. sizeof(HOOKPATCHINFO));
  2169. if (!pPatchInfo) {
  2170. DPF(("[SevExecutePatchPrimitive] Failure allocating pPatchInfo.\n"));
  2171. return STATUS_UNSUCCESSFUL;
  2172. }
  2173. pPatchHookList = (PHOOKPATCHINFO)pShimData->pHookPatchList;
  2174. if (0 != pActivateData->rva.address) {
  2175. pPatchInfo->pNextHook = pPatchHookList;
  2176. pPatchInfo->dwHookAddress = dwAddress;
  2177. pPatchInfo->pThunkAddress = pThunk;
  2178. pPatchInfo->pData = (PSETACTIVATEADDRESS)((DWORD)pActivateData + sizeof(SETACTIVATEADDRESS));
  2179. }
  2180. else {
  2181. pPatchInfo->pNextHook = pPatchHookList;
  2182. pPatchInfo->dwHookAddress = 0;
  2183. pPatchInfo->pThunkAddress = 0;
  2184. pPatchInfo->pData = (PSETACTIVATEADDRESS)((DWORD)pActivateData + sizeof(SETACTIVATEADDRESS));
  2185. }
  2186. //
  2187. // Add ourselves to the head of the list
  2188. //
  2189. pShimData->pHookPatchList = (PVOID)pPatchInfo;
  2190. //
  2191. // Break out since this is a continuation mode operation
  2192. //
  2193. bIteratePatch = FALSE;
  2194. break;
  2195. case PWD:
  2196. //
  2197. // This is a patch write data primitive - write the data
  2198. //
  2199. pWriteData = (PPATCHWRITEDATA)pPatchOP->data;
  2200. //
  2201. // Grab the physical address to do this operation
  2202. //
  2203. dwAddress = SevGetPatchAddress(&(pWriteData->rva));
  2204. if (0 == dwAddress) {
  2205. DPF(("[SevExecutePatchPrimitive] Failure SevGetPatchAddress.\n"));
  2206. return STATUS_UNSUCCESSFUL;
  2207. }
  2208. //
  2209. // Fixup the page attributes
  2210. //
  2211. dwProtectSize = pWriteData->dwSizeData;
  2212. dwProtectFuncAddress = dwAddress;
  2213. status = NtProtectVirtualMemory(NtCurrentProcess(),
  2214. (PVOID)&dwProtectFuncAddress,
  2215. &dwProtectSize,
  2216. PAGE_READWRITE,
  2217. &dwOldFlags);
  2218. if (status) {
  2219. DPF(("[SevExecutePatchPrimitive] Failure NtProtectVirtualMemory.\n"));
  2220. return STATUS_UNSUCCESSFUL;
  2221. }
  2222. //
  2223. // Copy our bytes
  2224. //
  2225. RtlCopyMemory((PVOID)dwAddress, (PVOID)pWriteData->data, pWriteData->dwSizeData);
  2226. //
  2227. // Restore the page protection
  2228. //
  2229. dwProtectSize = pWriteData->dwSizeData;
  2230. dwProtectFuncAddress = dwAddress;
  2231. status = NtProtectVirtualMemory(NtCurrentProcess(),
  2232. (PVOID)&dwProtectFuncAddress,
  2233. &dwProtectSize,
  2234. dwOldFlags,
  2235. &dwOldFlags);
  2236. if (status) {
  2237. DPF(("[SevExecutePatchPrimitive] Failure NtProtectVirtualMemory.\n"));
  2238. return STATUS_UNSUCCESSFUL;
  2239. }
  2240. status = NtFlushInstructionCache(NtCurrentProcess(),
  2241. (PVOID)dwProtectFuncAddress,
  2242. dwProtectSize);
  2243. if (!NT_SUCCESS(status)) {
  2244. DPF(("[SevExecutePatchPrimitive] NtFlushInstructionCache failed with status 0x%X.\n",
  2245. status));
  2246. }
  2247. //
  2248. // Next opcode
  2249. //
  2250. pPatch = (PBYTE)(pPatchOP->dwNextOpcode + (DWORD)pPatch);
  2251. break;
  2252. case PNOP:
  2253. //
  2254. // This is a patch no operation primitive - just ignore this and queue next op
  2255. //
  2256. //
  2257. // Next opcode
  2258. //
  2259. pPatch = (PBYTE)(pPatchOP->dwNextOpcode + (DWORD)pPatch);
  2260. break;
  2261. case PMAT:
  2262. //
  2263. // This is a patch match data at offset primitive
  2264. //
  2265. pMatchData = (PPATCHMATCHDATA)pPatchOP->data;
  2266. //
  2267. // Grab the physical address to do this operation
  2268. //
  2269. dwAddress = SevGetPatchAddress(&(pMatchData->rva));
  2270. if (0 == dwAddress) {
  2271. DPF(("[SevExecutePatchPrimitive] Failure SevGetPatchAddress.\n"));
  2272. return STATUS_UNSUCCESSFUL;
  2273. }
  2274. //
  2275. // Let's do a strncmp to verify our match
  2276. //
  2277. if (0 != strncmp(pMatchData->data, (PBYTE)dwAddress, pMatchData->dwSizeData)) {
  2278. DPF(("[SevExecutePatchPrimitive] Failure match on patch data.\n"));
  2279. return STATUS_UNSUCCESSFUL;
  2280. }
  2281. //
  2282. // Next opcode
  2283. //
  2284. pPatch = (PBYTE)(pPatchOP->dwNextOpcode + (DWORD)pPatch);
  2285. break;
  2286. default:
  2287. //
  2288. // If this happens we got an unexpected operation and we have to fail
  2289. //
  2290. return STATUS_UNSUCCESSFUL;
  2291. }
  2292. }
  2293. return status;
  2294. }
  2295. VOID
  2296. SevValidateGlobalFilter(VOID)
  2297. /*++
  2298. Routine Description:
  2299. This routine does a quick iteration of the global filter to revalidate the filter
  2300. address ranges of the DLLs not brought in through the original EXE imports
  2301. Arguments:
  2302. None.
  2303. Return Value:
  2304. Return is STATUS_SUCCESS if no problem occured
  2305. --*/
  2306. {
  2307. NTSTATUS status;
  2308. WCHAR *pwszDllName = 0;
  2309. PMODULEFILTER pModFilter = 0;
  2310. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  2311. PVOID ModuleHandle = 0;
  2312. UNICODE_STRING UnicodeString;
  2313. PIMAGE_NT_HEADERS NtHeaders = 0;
  2314. pShimData = (PAPP_COMPAT_SHIM_INFO)NtCurrentPeb()->pShimData;
  2315. pModFilter = (PMODULEFILTER)pShimData->pLBFilterList;
  2316. //
  2317. // Walk the global exclusion filter until we find this particular DLL load
  2318. //
  2319. while (pModFilter) {
  2320. //
  2321. // Fixup the addresses
  2322. //
  2323. RtlInitUnicodeString(&UnicodeString, pModFilter->wszModuleName);
  2324. //
  2325. // Make sure our module is loaded before calculating address ranges
  2326. //
  2327. status = LdrGetDllHandle(
  2328. NULL,
  2329. NULL,
  2330. &UnicodeString,
  2331. &ModuleHandle);
  2332. if (STATUS_SUCCESS != status) {
  2333. //
  2334. // DLL not loaded - next pModFilter entry
  2335. //
  2336. pModFilter = pModFilter->pNextLBFilter;
  2337. continue;
  2338. }
  2339. //
  2340. // Precalculate the caller address or call range
  2341. //
  2342. if (pModFilter->dwFlags & MODFILTER_DLL) {
  2343. //
  2344. // Set the address range
  2345. //
  2346. NtHeaders = RtlImageNtHeader(ModuleHandle);
  2347. pModFilter->dwModuleStart = (DWORD)ModuleHandle;
  2348. pModFilter->dwModuleEnd = pModFilter->dwModuleStart + (DWORD)(NtHeaders->OptionalHeader.SizeOfImage);
  2349. }
  2350. else {
  2351. //
  2352. // Address is filtered by specific call
  2353. //
  2354. pModFilter->dwCallerAddress = (DWORD)ModuleHandle + pModFilter->dwCallerOffset;
  2355. }
  2356. pModFilter = pModFilter->pNextLBFilter;
  2357. }
  2358. return;
  2359. }
  2360. PVOID
  2361. SevBuildInjectionCode(
  2362. PVOID pAddress,
  2363. PDWORD pdwThunkSize)
  2364. /*++
  2365. Routine Description:
  2366. This routine builds the call stub used in calling the originally hooked API.
  2367. Arguments:
  2368. pAddress - Pointer to the entry point for which we are building a stub.
  2369. Return Value:
  2370. Return is non-zero if a stub was able to be generated successfully.
  2371. --*/
  2372. {
  2373. DWORD dwPreThunkSize = 0;
  2374. DWORD dwInstruction = 0;
  2375. DWORD dwAdjustedInstruction = 0;
  2376. DWORD dwStreamLength = 0;
  2377. DWORD dwNumberOfCalls = 0;
  2378. DWORD dwCallNumber = 0;
  2379. DWORD dwSize = 0;
  2380. PDWORD pdwTranslationArray = 0;
  2381. PDWORD pdwRelativeAddress = 0;
  2382. PVOID pThunk = 0;
  2383. WORD SegCs = 0;
  2384. dwStreamLength = 0;
  2385. dwInstruction = 0;
  2386. dwNumberOfCalls = 0;
  2387. dwCallNumber = 0;
  2388. //
  2389. // Calculate the thunk size with any stream adjustments necessary for relative calls
  2390. //
  2391. while(dwInstruction < CLI_OR_STI_SIZE) {
  2392. if ( *(PBYTE)((DWORD)pAddress + dwInstruction) == (BYTE)X86_REL_CALL_OPCODE) {
  2393. dwNumberOfCalls++;
  2394. }
  2395. dwInstruction += GetInstructionLengthFromAddress((PVOID)((DWORD)pAddress + dwInstruction));
  2396. }
  2397. //
  2398. // Call dword [xxxx] is 6 bytes and call relative is 5.
  2399. //
  2400. dwPreThunkSize = dwInstruction;
  2401. dwStreamLength = dwInstruction + (1 * dwNumberOfCalls);
  2402. //
  2403. // Allocate our call dword [xxxx] translation array
  2404. //
  2405. if (dwNumberOfCalls) {
  2406. pdwTranslationArray = (PDWORD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  2407. HEAP_ZERO_MEMORY,
  2408. dwNumberOfCalls * sizeof(DWORD));
  2409. if (!pdwTranslationArray){
  2410. *pdwThunkSize = 0;
  2411. return pThunk;
  2412. }
  2413. }
  2414. //
  2415. // Allocate our instruction stream with the size of the absolute jmp included
  2416. //
  2417. pThunk = (*g_pfnRtlAllocateHeap)(g_pShimHeap,
  2418. HEAP_ZERO_MEMORY,
  2419. dwStreamLength + JMP_SIZE);
  2420. if ( !pThunk ){
  2421. *pdwThunkSize = 0;
  2422. return pThunk;
  2423. }
  2424. //
  2425. // Do any relative call translations
  2426. //
  2427. if (dwNumberOfCalls) {
  2428. dwInstruction = 0;
  2429. dwAdjustedInstruction = 0;
  2430. do
  2431. {
  2432. dwSize = GetInstructionLengthFromAddress((PVOID)((DWORD)pAddress + dwInstruction));
  2433. if (*(PBYTE)((DWORD)pAddress + dwInstruction) == (BYTE)X86_REL_CALL_OPCODE) {
  2434. //
  2435. // Calculate the call address (it's a dword following the opcode)
  2436. //
  2437. pdwRelativeAddress = (PDWORD)((DWORD)pAddress + dwInstruction + 1);
  2438. //
  2439. // Do the relative call translation
  2440. //
  2441. pdwTranslationArray[dwCallNumber] = *pdwRelativeAddress + (DWORD)pAddress + dwInstruction + CALL_REL_SIZE;
  2442. //
  2443. // Finally create the call dword code
  2444. //
  2445. *((BYTE *)((DWORD)pThunk + dwAdjustedInstruction)) = X86_CALL_OPCODE;
  2446. *((BYTE *)((DWORD)pThunk + dwAdjustedInstruction + 1)) = X86_CALL_OPCODE2;
  2447. *((DWORD *)((DWORD)pThunk + dwAdjustedInstruction + 1 + 1)) = (DWORD)&pdwTranslationArray[dwCallNumber];
  2448. //
  2449. // Make sure our index is in sync with our translation
  2450. //
  2451. dwCallNumber++;
  2452. dwAdjustedInstruction += CLI_OR_STI_SIZE;
  2453. }
  2454. else {
  2455. //
  2456. // Copy the instruction bytes across -- it's not a call
  2457. //
  2458. RtlMoveMemory((PVOID)((DWORD)pThunk + dwAdjustedInstruction),
  2459. (PVOID)((DWORD)pAddress + dwInstruction),
  2460. dwSize);
  2461. dwAdjustedInstruction += dwSize;
  2462. }
  2463. dwInstruction += dwSize;
  2464. }
  2465. while(dwInstruction < dwPreThunkSize);
  2466. }
  2467. else {
  2468. //
  2469. // Nothing to translate
  2470. //
  2471. RtlMoveMemory(pThunk, pAddress, dwStreamLength);
  2472. }
  2473. //
  2474. // Grab the code segment for the thunk (we use this to build our absolute jump)
  2475. //
  2476. _asm {
  2477. push cs
  2478. pop eax
  2479. mov SegCs, ax
  2480. }
  2481. //
  2482. // Add the absolute jmp to the end of the stub
  2483. //
  2484. *((BYTE *)(dwStreamLength + (DWORD)pThunk )) = X86_ABSOLUTE_FAR_JUMP;
  2485. *((DWORD *)(dwStreamLength + (DWORD)pThunk + 1)) = ((DWORD)pAddress + dwInstruction);
  2486. *((WORD *)(dwStreamLength + (DWORD)pThunk + 1 + 4)) = SegCs;
  2487. //
  2488. // Set the size of the call thunk
  2489. //
  2490. *pdwThunkSize = dwStreamLength + JMP_SIZE;
  2491. return pThunk;
  2492. }
  2493. DWORD
  2494. SevGetPatchAddress(PRELATIVE_MODULE_ADDRESS pRelAddress)
  2495. /*++
  2496. Routine Description:
  2497. This routine is designed to calculate an absolute address for a relative offset and
  2498. module name.
  2499. Arguments:
  2500. pRelAddress - Pointer to a RELATIVE_MODULE_ADDRESS data structure
  2501. Return Value:
  2502. Return is non-zero if an address was calculatable, otherwise 0 is returned for failure.
  2503. --*/
  2504. {
  2505. WCHAR wszModule[MAX_PATH*2];
  2506. PVOID ModuleHandle = 0;
  2507. UNICODE_STRING UnicodeString;
  2508. DWORD dwAddress = 0;
  2509. NTSTATUS status;
  2510. PPEB Peb = 0;
  2511. Peb = NtCurrentPeb();
  2512. if (pRelAddress->moduleName[0] != L'\0') {
  2513. //
  2514. // Copy the module name from the patch since it will typically be misaligned
  2515. //
  2516. wcscpy(wszModule, pRelAddress->moduleName);
  2517. //
  2518. // Look up the module name and get the base address
  2519. //
  2520. //
  2521. // Is this DLL mapped in the address space?
  2522. //
  2523. RtlInitUnicodeString(&UnicodeString, wszModule);
  2524. //
  2525. // Make sure our module is loaded before calculating address ranges
  2526. //
  2527. status = LdrGetDllHandle(
  2528. NULL,
  2529. NULL,
  2530. &UnicodeString,
  2531. &ModuleHandle);
  2532. if (STATUS_SUCCESS != status) {
  2533. //
  2534. // This module should be present and it isn't - bail
  2535. //
  2536. DPF(("[SevGetPatchAddress] Failure LdrGetDllHandle.\n"));
  2537. return 0;
  2538. }
  2539. //
  2540. // We're done, return the address
  2541. //
  2542. return ( (DWORD)ModuleHandle + pRelAddress->address );
  2543. }
  2544. else {
  2545. //
  2546. // Go to the PEB and we're done
  2547. //
  2548. dwAddress = (DWORD)Peb->ImageBaseAddress + pRelAddress->address;
  2549. return dwAddress;
  2550. }
  2551. DPF(("[SevGetPatchAddress] Failure; reached end of function.\n"));
  2552. return 0;
  2553. }
  2554. NTSTATUS
  2555. StubLdrLoadDll (
  2556. IN PWSTR DllPath OPTIONAL,
  2557. IN PULONG DllCharacteristics OPTIONAL,
  2558. IN PUNICODE_STRING DllName,
  2559. OUT PVOID *DllHandle
  2560. )
  2561. /*++
  2562. Routine Description:
  2563. This is the stub API entry which catches all the dynamic DLL loading events. This
  2564. routine is responsible for catching all the dynamic loading DLLs (non-import bound)
  2565. with the intent of fixing up of their entry points so that they are "shimed"
  2566. Arguments:
  2567. DllPath - See LdrLoadDll for a description of the parameters
  2568. DllCharacteristics -
  2569. DllName -
  2570. DllHandle -
  2571. Return Value:
  2572. Return is STATUS_SUCCESS if no problem occured
  2573. --*/
  2574. {
  2575. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  2576. PFNLDRLOADDLL pfnOldFunction = 0;
  2577. DWORD dwHookCount = 0;
  2578. PHOOKAPI *pHookArray = 0;
  2579. NTSTATUS status;
  2580. DWORD dwCounter = 0;
  2581. PDWORD pdwHookArrayCount = 0;
  2582. DWORD dwUnhookedCount = 0;
  2583. PPEB Peb = 0;
  2584. Peb = NtCurrentPeb();
  2585. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  2586. pfnOldFunction = g_InternalHookArray[0].pfnOld;
  2587. status = (*pfnOldFunction)(DllPath,
  2588. DllCharacteristics,
  2589. DllName,
  2590. DllHandle);
  2591. //
  2592. // See if there's anything to hook with this module
  2593. //
  2594. if ( STATUS_SUCCESS == status ){
  2595. dwHookCount = pShimData->dwHookAPICount;
  2596. pHookArray = pShimData->ppHookAPI;
  2597. //
  2598. // There may not be any functions to hook
  2599. //
  2600. if (0 == dwHookCount) {
  2601. //
  2602. // Just return status as we're not needing to look for functions loading dynamically
  2603. //
  2604. return status;
  2605. }
  2606. pdwHookArrayCount = (PDWORD)(*g_pfnRtlAllocateHeap)(g_pShimHeap,
  2607. HEAP_ZERO_MEMORY,
  2608. sizeof(DWORD) * pShimData->dwHookAPICount);
  2609. if (!pdwHookArrayCount) {
  2610. DPF(("[StubLdrLoadDll] Failure allocating pdwHookArrayCount.\n"));
  2611. return status;
  2612. }
  2613. for (dwCounter = 0; dwCounter < dwHookCount; dwCounter++) {
  2614. pdwHookArrayCount[dwCounter] = 1;
  2615. }
  2616. RtlEnterCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  2617. SevFixupAvailableProcs(dwHookCount,
  2618. pHookArray,
  2619. pdwHookArrayCount,
  2620. &dwUnhookedCount);
  2621. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  2622. //
  2623. // Don't care about success/failure
  2624. //
  2625. (*g_pfnRtlFreeHeap)(g_pShimHeap,
  2626. 0,
  2627. pdwHookArrayCount);
  2628. }
  2629. return status;
  2630. }
  2631. NTSTATUS
  2632. StubLdrUnloadDll (
  2633. IN PVOID DllHandle
  2634. )
  2635. /*++
  2636. Routine Description:
  2637. This is the stub API entry which catches all the dynamic DLL unloading events. we
  2638. are here to do simple bookkeeping on what dyanamic DLLs API hooks are valid.
  2639. Arguments:
  2640. DllHandle - Pointer to the base address of the unloading module
  2641. Return Value:
  2642. Return is STATUS_SUCCESS if no problem occured
  2643. --*/
  2644. {
  2645. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  2646. PFNLDRUNLOADDLL pfnOldFunction = 0;
  2647. PHOOKAPIINFO pAPIHookList = 0;
  2648. PHOOKAPIINFO pTempHook = 0;
  2649. PHOOKAPI pHookTemp = 0;
  2650. ANSI_STRING AnsiString;
  2651. UNICODE_STRING UnicodeString;
  2652. PVOID ModuleHandle = 0;
  2653. NTSTATUS status;
  2654. NTSTATUS status2;
  2655. PPEB Peb = 0;
  2656. Peb = NtCurrentPeb();
  2657. pShimData = (PAPP_COMPAT_SHIM_INFO)Peb->pShimData;
  2658. pfnOldFunction = g_InternalHookArray[1].pfnOld;
  2659. status = (*pfnOldFunction)(DllHandle);
  2660. //
  2661. // See if we lost any hooks during this unload event
  2662. //
  2663. if ( STATUS_SUCCESS == status ){
  2664. //
  2665. // Walk the dyanamic list and drop any hooks which no longer have loaded modules
  2666. //
  2667. pAPIHookList = pShimData->pHookAPIList;
  2668. while (pAPIHookList) {
  2669. //
  2670. // Is the module this hook belongs to unmapped now?
  2671. //
  2672. RtlInitUnicodeString(&UnicodeString, pAPIHookList->wszModuleName);
  2673. status = LdrGetDllHandle(
  2674. NULL,
  2675. NULL,
  2676. &UnicodeString,
  2677. &ModuleHandle);
  2678. if (STATUS_SUCCESS != status) {
  2679. //
  2680. // Ok, hooks on this module needs to go away now
  2681. //
  2682. RtlEnterCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  2683. //
  2684. // Clear the chaining flags since this API chain is going away
  2685. //
  2686. pHookTemp = pAPIHookList->pTopLevelAPIChain;
  2687. while (pHookTemp) {
  2688. pHookTemp->dwFlags &= HOOK_INDEX_MASK;
  2689. pHookTemp = pHookTemp->pNextHook;
  2690. }
  2691. //
  2692. // Save off pAPIHookList hook entry since its going away here shortly
  2693. //
  2694. pTempHook = pAPIHookList;
  2695. //
  2696. // Delete the node from the list
  2697. //
  2698. if (pTempHook->pNextHook) {
  2699. pTempHook->pNextHook->pPrevHook = pTempHook->pPrevHook;
  2700. }
  2701. if (pTempHook->pPrevHook) {
  2702. pTempHook->pPrevHook->pNextHook = pTempHook->pNextHook;
  2703. }
  2704. else {
  2705. pShimData->pHookAPIList = (PVOID)pTempHook->pNextHook;
  2706. }
  2707. RtlLeaveCriticalSection((CRITICAL_SECTION *)pShimData->pCritSec);
  2708. //
  2709. // Set our next API hook pointer
  2710. //
  2711. pAPIHookList = pTempHook->pNextHook;
  2712. //
  2713. // If we allocated memory for a shim chain stub, free this memory
  2714. //
  2715. if (pTempHook->pTopLevelAPIChain->pNextHook == 0 &&
  2716. pTempHook->pTopLevelAPIChain->pszFunctionName == 0) {
  2717. (*g_pfnRtlFreeHeap)(g_pShimHeap,
  2718. 0,
  2719. pTempHook->pTopLevelAPIChain);
  2720. }
  2721. //
  2722. // Dump the thunk data and this struct allocation
  2723. //
  2724. (*g_pfnRtlFreeHeap)(g_pShimHeap,
  2725. 0,
  2726. pTempHook->pCallThunkAddress);
  2727. (*g_pfnRtlFreeHeap)(g_pShimHeap,
  2728. 0,
  2729. pTempHook);
  2730. //
  2731. // Next API hook
  2732. //
  2733. continue;
  2734. }
  2735. pAPIHookList = pAPIHookList->pNextHook;
  2736. }
  2737. }
  2738. return status;
  2739. }
  2740. PVOID
  2741. SevFilterCaller(
  2742. PMODULEFILTER pFilterList,
  2743. PVOID pFunctionAddress,
  2744. PVOID pExceptionAddress,
  2745. PVOID pStubAddress,
  2746. PVOID pCallThunkAddress)
  2747. /*++
  2748. Routine Description:
  2749. This is a stub routine called by the shim to validate whether or not to process a given
  2750. hooked instance.
  2751. Arguments:
  2752. pFilterList - List of exceptions to be applied against the caller
  2753. pFunctionAddress - Address of the API/Function being filtered
  2754. pExceptionAddress - Address of the exception to filter (caller address)
  2755. pStubAddress - Address of the top level stub function
  2756. pCallThunkAddress - Address of the call thunk to the original function
  2757. Return Value:
  2758. If the call is not filtered then pStubAddress is returned, otherwise pCallThunkAddress is returned to
  2759. avoid the shim call.
  2760. --*/
  2761. {
  2762. PAPP_COMPAT_SHIM_INFO pShimData = 0;
  2763. pShimData = (PAPP_COMPAT_SHIM_INFO)NtCurrentPeb()->pShimData;
  2764. //
  2765. // If this is a call for LdrLoadDLL or LdrUnloadDLL then we need to not filter these out
  2766. //
  2767. if ( (DWORD)g_pfnOldLdrUnloadDLL == (DWORD)pFunctionAddress ||
  2768. (DWORD)g_pfnOldLdrLoadDLL == (DWORD)pFunctionAddress) {
  2769. return pStubAddress;
  2770. }
  2771. //
  2772. // Walk the exe filter for any specific inclusions/exclusions
  2773. //
  2774. while(pFilterList) {
  2775. //
  2776. // See if this is a global filtering or just for one call
  2777. //
  2778. if (pFilterList->dwFlags & MODFILTER_GLOBAL) {
  2779. //
  2780. // Apply the filter logic based on flags
  2781. //
  2782. if (pFilterList->dwFlags & MODFILTER_INCLUDE) {
  2783. return pStubAddress;
  2784. }
  2785. else {
  2786. return pCallThunkAddress;
  2787. }
  2788. }
  2789. else if (pFilterList->dwFlags & MODFILTER_DLL) {
  2790. //
  2791. // Global check the caller
  2792. //
  2793. if ((DWORD)pExceptionAddress >= pFilterList->dwModuleStart &&
  2794. (DWORD)pExceptionAddress <= pFilterList->dwModuleEnd) {
  2795. //
  2796. // Apply the filter logic based on flags
  2797. //
  2798. if (pFilterList->dwFlags & MODFILTER_INCLUDE) {
  2799. return pStubAddress;
  2800. }
  2801. else {
  2802. return pCallThunkAddress;
  2803. }
  2804. }
  2805. }
  2806. else {
  2807. //
  2808. // Quick check the caller
  2809. //
  2810. if ((DWORD)pExceptionAddress == pFilterList->dwCallerAddress) {
  2811. //
  2812. // Apply the filter logic based on flags
  2813. //
  2814. if (pFilterList->dwFlags & MODFILTER_INCLUDE) {
  2815. return pStubAddress;
  2816. }
  2817. else {
  2818. return pCallThunkAddress;
  2819. }
  2820. }
  2821. }
  2822. pFilterList = pFilterList->pNextFilter;
  2823. }
  2824. //
  2825. // Check the global filter for any specific inclusions/exclusions
  2826. //
  2827. pFilterList = (PMODULEFILTER)pShimData->pGlobalFilterList;
  2828. while(pFilterList) {
  2829. //
  2830. // See if this is a global filtering or just for one call
  2831. //
  2832. if (pFilterList->dwFlags & MODFILTER_DLL) {
  2833. //
  2834. // Global check the caller
  2835. //
  2836. if ((DWORD)pExceptionAddress >= pFilterList->dwModuleStart &&
  2837. (DWORD)pExceptionAddress <= pFilterList->dwModuleEnd) {
  2838. //
  2839. // Apply the filter logic based on flags
  2840. //
  2841. if (pFilterList->dwFlags & MODFILTER_INCLUDE) {
  2842. return pStubAddress;
  2843. }
  2844. else {
  2845. return pCallThunkAddress;
  2846. }
  2847. }
  2848. }
  2849. else {
  2850. //
  2851. // Quick check the caller
  2852. //
  2853. if ((DWORD)pExceptionAddress == pFilterList->dwCallerAddress) {
  2854. //
  2855. // Apply the filter logic based on flags
  2856. //
  2857. if (pFilterList->dwFlags & MODFILTER_INCLUDE) {
  2858. return pStubAddress;
  2859. }
  2860. else {
  2861. return pCallThunkAddress;
  2862. }
  2863. }
  2864. }
  2865. pFilterList = pFilterList->pNextFilter;
  2866. }
  2867. //
  2868. // Call wasn't filtered - default to include any chain
  2869. //
  2870. return pStubAddress;
  2871. }
  2872. NTSTATUS
  2873. SevFinishThunkInjection (
  2874. DWORD dwAddress,
  2875. PVOID pThunk,
  2876. DWORD dwThunkSize,
  2877. BYTE jReason)
  2878. /*++
  2879. Routine Description:
  2880. This routine takes a generated thunk and fixes up its page protections. It also finishes the
  2881. injection process by putting the thunk mechanism into the entrypoint of the hooked function.
  2882. For patches this code path is the same since the same fixup are done for arbitrary data we
  2883. want to patch dynamically.
  2884. Arguments:
  2885. dwAddress - Entrypoint of a function which is being hooked
  2886. pThunk - Address of the thunk generated for the function being hooked
  2887. dwThunkSize - Size of the thunk passed here to be finalized.
  2888. jReason - byte which is used to determine the filter exception type
  2889. Return Value:
  2890. STATUS_SUCCESS is returned if everything happened as expected.
  2891. --*/
  2892. {
  2893. DWORD dwProtectSize;
  2894. DWORD dwProtectFuncAddress;
  2895. DWORD dwOldFlags = 0;
  2896. NTSTATUS status;
  2897. //
  2898. // Mark this code for execution
  2899. //
  2900. dwProtectSize = dwThunkSize;
  2901. dwProtectFuncAddress = (DWORD)pThunk;
  2902. status = NtProtectVirtualMemory(NtCurrentProcess(),
  2903. (PVOID)&dwProtectFuncAddress,
  2904. &dwProtectSize,
  2905. PAGE_EXECUTE_READWRITE,
  2906. &dwOldFlags);
  2907. if (status) {
  2908. DPF(("[SevFinishThunkInjection] Failure NtProtectVirtualMemory.\n"));
  2909. return STATUS_UNSUCCESSFUL;
  2910. }
  2911. //
  2912. // Fixup the page attributes
  2913. //
  2914. dwProtectSize = CLI_OR_STI_SIZE;
  2915. dwProtectFuncAddress = dwAddress;
  2916. status = NtProtectVirtualMemory(NtCurrentProcess(),
  2917. (PVOID)&dwProtectFuncAddress,
  2918. &dwProtectSize,
  2919. PAGE_EXECUTE_READWRITE,
  2920. &dwOldFlags);
  2921. if (status) {
  2922. DPF(("[SevFinishThunkInjection] Failure NtProtectVirtualMemory.\n"));
  2923. return STATUS_UNSUCCESSFUL;
  2924. }
  2925. //
  2926. // Insert the CALL
  2927. //
  2928. *((BYTE*)(dwAddress)) = jReason;
  2929. //
  2930. // Restore the page protection
  2931. //
  2932. dwProtectSize = CLI_OR_STI_SIZE;
  2933. dwProtectFuncAddress = dwAddress;
  2934. status = NtProtectVirtualMemory(NtCurrentProcess(),
  2935. (PVOID)&dwProtectFuncAddress,
  2936. &dwProtectSize,
  2937. dwOldFlags,
  2938. &dwOldFlags);
  2939. if (status) {
  2940. DPF(("[SevFinishThunkInjection] Failure NtProtectVirtualMemory.\n"));
  2941. return STATUS_UNSUCCESSFUL;
  2942. }
  2943. status = NtFlushInstructionCache(NtCurrentProcess(),
  2944. (PVOID)dwProtectFuncAddress,
  2945. dwProtectSize);
  2946. if (!NT_SUCCESS(status)) {
  2947. DPF(("[SevFinishThunkInjection] NtFlushInstructionCache failed !!!.\n"));
  2948. return STATUS_UNSUCCESSFUL;
  2949. }
  2950. return STATUS_SUCCESS;
  2951. }
  2952. void
  2953. SE_ProcessDying(
  2954. void
  2955. )
  2956. {
  2957. return;
  2958. }
  2959. BOOL WINAPI
  2960. DllMain(
  2961. HINSTANCE hInstance,
  2962. DWORD dwreason,
  2963. LPVOID reserved
  2964. )
  2965. {
  2966. return TRUE;
  2967. }