Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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