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

1446 lines
40 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Win2kPropagateLayer.cpp
  5. Abstract:
  6. This shim propagates a layer from a process to its child processes on Win2k.
  7. Notes:
  8. This is a layer shim.
  9. History:
  10. 03/13/2000 clupu Created
  11. 10/26/2000 Vadimb Merged WowProcessHistory functionality, new environment-handling cases
  12. --*/
  13. #include "precomp.h"
  14. IMPLEMENT_SHIM_BEGIN(Win2kPropagateLayer)
  15. #include "ShimHookMacro.h"
  16. #include "Win2kPropagateLayer.h"
  17. #include "stdio.h"
  18. APIHOOK_ENUM_BEGIN
  19. APIHOOK_ENUM_ENTRY(CreateProcessA)
  20. APIHOOK_ENUM_ENTRY(CreateProcessW)
  21. APIHOOK_ENUM_ENTRY(UserRegisterWowHandlers)
  22. APIHOOK_ENUM_END
  23. #define LI_WIN95 0x00000001
  24. #define LI_NT4 0x00000002
  25. #define LI_WIN98 0x00000004
  26. #define LS_MAGIC 0x07036745
  27. typedef struct tagLayerStorageHeader {
  28. DWORD dwItemCount; // number of items in the file
  29. DWORD dwMagic; // magic to identify the file
  30. SYSTEMTIME timeLast; // time of last access
  31. } LayerStorageHeader, *PLayerStorageHeader;
  32. typedef struct tagLayeredItem {
  33. WCHAR szItemName[MAX_PATH];
  34. DWORD dwFlags;
  35. } LayeredItem, *PLayeredItem;
  36. #define APPCOMPAT_KEY L"System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility"
  37. WCHAR g_szLayerStorage[MAX_PATH] = L"";
  38. CHAR g_szCompatLayerVar[] = "__COMPAT_LAYER";
  39. CHAR g_szProcessHistoryVar[] = "__PROCESS_HISTORY";
  40. CHAR g_szShimFileLogVar[] = "SHIM_FILE_LOG";
  41. WCHAR g_wszCompatLayerVar[] = L"__COMPAT_LAYER";
  42. WCHAR g_wszProcessHistroyVar[] = L"__PROCESS_HISTORY";
  43. //
  44. // This variable receives current process' compat layer
  45. //
  46. WCHAR* g_pwszCompatLayer = NULL;
  47. WCHAR* g_pwszProcessHistory = NULL;
  48. //
  49. // Unicode equivalent of the above
  50. //
  51. UNICODE_STRING g_ustrProcessHistoryVar = RTL_CONSTANT_STRING(L"__PROCESS_HISTORY");
  52. UNICODE_STRING g_ustrCompatLayerVar = RTL_CONSTANT_STRING(L"__COMPAT_LAYER");
  53. //
  54. // Global flags
  55. //
  56. BOOL g_bIsNTVDM = FALSE;
  57. BOOL g_bIsExplorer = FALSE;
  58. INT g_argc = 0;
  59. CHAR** g_argv = NULL;
  60. //
  61. // is this a separate wow ?
  62. //
  63. BOOL* g_pSeparateWow = NULL;
  64. BOOL
  65. InitLayerStorage(
  66. BOOL bDelete
  67. )
  68. {
  69. if (GetSystemWindowsDirectoryW(g_szLayerStorage, MAX_PATH) >= MAX_PATH) {
  70. return FALSE;
  71. }
  72. if (lstrlenW(g_szLayerStorage) >= 1 && g_szLayerStorage[lstrlenW(g_szLayerStorage) - 1] == L'\\') {
  73. g_szLayerStorage[lstrlenW(g_szLayerStorage) - 1] = 0;
  74. }
  75. if (FAILED(StringCchCatW(g_szLayerStorage, MAX_PATH, L"\\AppPatch\\LayerStorage.dat"))) {
  76. return FALSE;
  77. }
  78. if (bDelete) {
  79. DeleteFileW(g_szLayerStorage);
  80. }
  81. return TRUE;
  82. }
  83. void
  84. ReadLayeredStorage(
  85. LPWSTR pszItem,
  86. LPDWORD lpdwFlags
  87. )
  88. {
  89. HANDLE hFile = INVALID_HANDLE_VALUE;
  90. HANDLE hFileMapping = NULL;
  91. DWORD dwFileSize;
  92. PBYTE pData = NULL;
  93. PLayerStorageHeader pHeader = NULL;
  94. PLayeredItem pItems;
  95. PLayeredItem pCrtItem = NULL;
  96. int nLeft, nRight, nMid, nItem;
  97. LOGN(
  98. eDbgLevelInfo,
  99. "[ReadLayeredStorage] for \"%S\"",
  100. pszItem);
  101. //
  102. // Make sure we don't corrupt the layer storage.
  103. //
  104. if (lstrlenW(pszItem) + 1 > MAX_PATH) {
  105. pszItem[MAX_PATH - 1] = 0;
  106. }
  107. hFile = CreateFileW(g_szLayerStorage,
  108. GENERIC_READ | GENERIC_WRITE,
  109. FILE_SHARE_READ | FILE_SHARE_WRITE,
  110. NULL,
  111. OPEN_EXISTING,
  112. 0,
  113. NULL);
  114. if (hFile == INVALID_HANDLE_VALUE) {
  115. LOGN(
  116. eDbgLevelInfo,
  117. "[ReadLayeredStorage] the layer storage doesn't exist.");
  118. *lpdwFlags = 0;
  119. return;
  120. }
  121. //
  122. // The file already exists. Create a file mapping that will allow
  123. // for querying the item.
  124. //
  125. dwFileSize = GetFileSize(hFile, NULL);
  126. hFileMapping = CreateFileMapping(hFile,
  127. NULL,
  128. PAGE_READWRITE,
  129. 0,
  130. dwFileSize,
  131. NULL);
  132. if (hFileMapping == NULL) {
  133. LOGN(
  134. eDbgLevelError,
  135. "[ReadLayeredStorage] CreateFileMapping failed 0x%X",
  136. GetLastError());
  137. goto done;
  138. }
  139. pData = (PBYTE)MapViewOfFile(hFileMapping,
  140. FILE_MAP_READ | FILE_MAP_WRITE,
  141. 0,
  142. 0,
  143. 0);
  144. if (pData == NULL) {
  145. LOGN(
  146. eDbgLevelError,
  147. "[ReadLayeredStorage] MapViewOfFile failed 0x%X",
  148. GetLastError());
  149. goto done;
  150. }
  151. pHeader = (PLayerStorageHeader)pData;
  152. pItems = (PLayeredItem)(pData + sizeof(LayerStorageHeader));
  153. //
  154. // Make sure it's our file.
  155. //
  156. if (dwFileSize < sizeof(LayerStorageHeader) || pHeader->dwMagic != LS_MAGIC) {
  157. LOGN(
  158. eDbgLevelError,
  159. "[ReadLayeredStorage] invalid file magic 0x%X",
  160. pHeader->dwMagic);
  161. goto done;
  162. }
  163. //
  164. // First search for the item. The array is sorted so we do binary search.
  165. //
  166. nItem = -1, nLeft = 0, nRight = (int)pHeader->dwItemCount - 1;
  167. while (nLeft <= nRight) {
  168. int nVal;
  169. nMid = (nLeft + nRight) / 2;
  170. pCrtItem = pItems + nMid;
  171. nVal = _wcsnicmp(pszItem, pCrtItem->szItemName, lstrlenW(pCrtItem->szItemName));
  172. if (nVal == 0) {
  173. nItem = nMid;
  174. break;
  175. } else if (nVal < 0) {
  176. nRight = nMid - 1;
  177. } else {
  178. nLeft = nMid + 1;
  179. }
  180. }
  181. if (nItem == -1) {
  182. LOGN(
  183. eDbgLevelInfo,
  184. "[ReadLayeredStorage] the item was not found in the file.");
  185. *lpdwFlags = 0;
  186. } else {
  187. //
  188. // The item is in the file.
  189. //
  190. LOGN(
  191. eDbgLevelInfo,
  192. "[ReadLayeredStorage] the item is in the file.");
  193. *lpdwFlags = pCrtItem->dwFlags;
  194. }
  195. done:
  196. if (pData != NULL) {
  197. UnmapViewOfFile(pData);
  198. }
  199. if (hFileMapping != NULL) {
  200. CloseHandle(hFileMapping);
  201. }
  202. if (hFile != INVALID_HANDLE_VALUE) {
  203. CloseHandle(hFile);
  204. }
  205. }
  206. BOOL
  207. GetFileNameFromCmdLine(
  208. LPWSTR lpFileName,
  209. DWORD dwFileNameSize,
  210. LPCWSTR lpCmdLine
  211. )
  212. {
  213. LPCWSTR pSrc = lpCmdLine;
  214. LPCWSTR pStart;
  215. BOOL bQuote = FALSE;
  216. BOOL bInitialQuote = FALSE;
  217. BOOL bDone = FALSE;
  218. DWORD dwLength; // length of the result, in chars
  219. pSrc += wcsspn(pSrc, L" \t");
  220. if (*pSrc == L'\"') {
  221. ++pSrc;
  222. bQuote = TRUE;
  223. bInitialQuote = TRUE;
  224. }
  225. pStart = pSrc; // note -- we're past the quote
  226. // we end when: 1) we start we the quote -- we end with the quote or
  227. // we did not start with the quote -- we encounter space then
  228. while (*pSrc && !bDone) {
  229. switch(*pSrc) {
  230. case L'\"':
  231. bQuote = !bQuote;
  232. break;
  233. case L' ':
  234. bDone = !bQuote; // out of quotes? this is the end
  235. break;
  236. }
  237. if (!bDone) {
  238. ++pSrc;
  239. }
  240. }
  241. if (pSrc > pStart && bInitialQuote && *(pSrc-1) == L'\"') {
  242. --pSrc;
  243. }
  244. //
  245. // now that we ended the run, copy
  246. //
  247. dwLength = (DWORD)(pSrc - pStart);
  248. if (dwFileNameSize < (dwLength + 1)) {
  249. // too big
  250. LOGN( eDbgLevelError,
  251. "[GetFileNameFromCmdLine] filename is too long\"%S\".\n", lpCmdLine);
  252. return FALSE;
  253. }
  254. RtlCopyMemory(lpFileName, pStart, dwLength * sizeof(WCHAR));
  255. lpFileName[dwLength] = L'\0';
  256. return TRUE;
  257. }
  258. BOOL
  259. AddSupport(
  260. LPCWSTR lpCommandLine,
  261. LPVOID* ppEnvironment,
  262. LPDWORD lpdwCreationFlags
  263. )
  264. {
  265. WCHAR szKey[MAX_PATH];
  266. WCHAR szFullPath[MAX_PATH + 3] = L"\"";
  267. WCHAR szExeName[MAX_PATH + 1];
  268. HKEY hkey;
  269. DWORD type;
  270. DWORD cbData = 0;
  271. BOOL bBraket = FALSE;
  272. LPVOID pEnvironmentNew = NULL;
  273. DWORD dwCreationFlags = *lpdwCreationFlags;
  274. BOOL bUserEnvironment = (*ppEnvironment != NULL);
  275. NTSTATUS Status;
  276. LPCWSTR pszEnd;
  277. LPCWSTR pszStart = lpCommandLine;
  278. //
  279. // Need to look in lpCommandLine for the first token
  280. //
  281. LPCWSTR psz = lpCommandLine;
  282. while (*psz == L' ' || *psz == L'\t') {
  283. psz++;
  284. }
  285. if (*psz == L'\"') {
  286. pszStart = psz + 1;
  287. bBraket = TRUE;
  288. } else {
  289. pszStart = psz;
  290. }
  291. while (*psz != 0) {
  292. if (*psz == L'\"') {
  293. bBraket = !bBraket;
  294. } else if (*psz == L' ' && !bBraket) {
  295. break;
  296. }
  297. psz++;
  298. }
  299. pszEnd = psz;
  300. //
  301. // Now walk back to get the caracters.
  302. //
  303. psz--;
  304. // Be careful not to walk back past the beginning of the command line.
  305. if (psz > lpCommandLine && *psz == L'\"') {
  306. psz--;
  307. pszEnd--;
  308. }
  309. // Don't under- or over-flow.
  310. // szFullPath is of size MAX_PATH + 3. We can copy in:
  311. // MAX_PATH + 3 - 2 (quotes) - 1 (NULL) = MAX_PATH characters.
  312. if( pszEnd <= pszStart || pszEnd - pszStart > MAX_PATH ) {
  313. return FALSE;
  314. }
  315. memcpy(szFullPath + 1, pszStart, (pszEnd - pszStart) * sizeof(WCHAR));
  316. szFullPath[pszEnd - pszStart + 1] = L'\"';
  317. szFullPath[pszEnd - pszStart + 2] = 0;
  318. pszStart = lpCommandLine;
  319. pszEnd = psz + 1;
  320. while (psz >= lpCommandLine) {
  321. if (*psz == L'\\') {
  322. pszStart = psz + 1;
  323. break;
  324. }
  325. psz--;
  326. }
  327. // We already know that pszEnd - pszStart is <= MAX_PATH because, since the
  328. // test above, we have only possibly reduced the size. Since szExeName is of
  329. // size MAX_PATH + 1, we are okay to do the memcopy.
  330. memcpy(szExeName, pszStart, (pszEnd - pszStart) * sizeof(WCHAR));
  331. szExeName[pszEnd - pszStart] = 0;
  332. if (g_bIsExplorer) {
  333. DWORD dwFlags = 0;
  334. ReadLayeredStorage(szFullPath, &dwFlags);
  335. if (dwFlags != LI_WIN95 && dwFlags != LI_NT4 && dwFlags != LI_WIN98) {
  336. //
  337. // no layer support
  338. //
  339. LOGN(
  340. eDbgLevelInfo,
  341. "[AddSupport] No Layer specified for \"%S\".",
  342. lpCommandLine);
  343. return TRUE;
  344. }
  345. // we are using layer -- clone the environment
  346. Status = ShimCloneEnvironment(&pEnvironmentNew, *ppEnvironment, !!(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT));
  347. if (!NT_SUCCESS(Status)) {
  348. LOGN(
  349. eDbgLevelError,
  350. "[AddSupport] Failed to Clone the environment. Status = 0x%x",
  351. Status);
  352. return FALSE;
  353. }
  354. if (LI_WIN95 == dwFlags) {
  355. Status = ShimSetEnvironmentVar(&pEnvironmentNew, g_wszCompatLayerVar, L"Win95");
  356. LOGN( eDbgLevelInfo, "[AddSupport] Env var \"Win95\" added.");
  357. } else if (LI_WIN98 == dwFlags) {
  358. Status = ShimSetEnvironmentVar(&pEnvironmentNew, g_wszCompatLayerVar, L"Win98");
  359. LOGN( eDbgLevelInfo, "[AddSupport] Env var \"Win98\" added.");
  360. } else if (LI_NT4 == dwFlags) {
  361. Status = ShimSetEnvironmentVar(&pEnvironmentNew, g_wszCompatLayerVar, L"NT4SP5");
  362. LOGN( eDbgLevelInfo, "[AddSupport] Env var \"NT4SP5\" added.");
  363. }
  364. if (!NT_SUCCESS(Status)) {
  365. LOGN(
  366. eDbgLevelError,
  367. "[AddSupport] Failed to set the environment variable. Status = 0x%x",
  368. Status);
  369. ShimFreeEnvironment(pEnvironmentNew);
  370. return FALSE;
  371. }
  372. //
  373. // We have succeeded, set the output values.
  374. //
  375. *ppEnvironment = pEnvironmentNew;
  376. *lpdwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
  377. } else {
  378. //
  379. // not explorer - set the environment variable up
  380. // compat_layer will be inherited by the child process if bUserEnvironment is FALSE
  381. //
  382. if (bUserEnvironment) {
  383. //
  384. // Clone the environment and add the layer variable to the new env.
  385. //
  386. Status = ShimCloneEnvironment(&pEnvironmentNew,
  387. *ppEnvironment,
  388. !!(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT));
  389. if (!NT_SUCCESS(Status)) {
  390. LOGN(
  391. eDbgLevelError,
  392. "[AddSupport] Failed to clone the environment. Status = 0x%x",
  393. Status);
  394. return FALSE;
  395. }
  396. Status = ShimSetEnvironmentVar(&pEnvironmentNew,
  397. g_wszCompatLayerVar,
  398. g_pwszCompatLayer);
  399. if (!NT_SUCCESS(Status)) {
  400. ShimFreeEnvironment(pEnvironmentNew);
  401. LOGN(
  402. eDbgLevelError,
  403. "[AddSupport] Failed to set compat layer variable. Status = 0x%x",
  404. Status);
  405. return FALSE;
  406. }
  407. LOGN(
  408. eDbgLevelInfo,
  409. "[AddSupport] Env var \"%S\" added.",
  410. g_pwszCompatLayer);
  411. *ppEnvironment = pEnvironmentNew;
  412. *lpdwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
  413. }
  414. }
  415. //
  416. // Build the registry key.
  417. //
  418. if( FAILED(StringCchPrintfW(szKey, MAX_PATH, L"%s\\%s", APPCOMPAT_KEY, szExeName)) )
  419. {
  420. return FALSE;
  421. }
  422. if (RegCreateKeyW(HKEY_LOCAL_MACHINE, szKey, &hkey) != ERROR_SUCCESS) {
  423. LOGN(
  424. eDbgLevelError,
  425. "Failed to open/create the appcompat key \"%s\"",
  426. szKey);
  427. } else {
  428. if (RegQueryValueExA(hkey, "DllPatch-x", NULL, &type, NULL, &cbData) != ERROR_SUCCESS) {
  429. BYTE data[16] = {0x0c, 0, 0, 0, 0, 0, 0, 0,
  430. 0x06, 0, 0, 0, 0, 0, 0, 0};
  431. //
  432. // The value doesn't exist. Create it.
  433. //
  434. RegSetValueExA(hkey,
  435. "y",
  436. NULL,
  437. REG_BINARY,
  438. data,
  439. sizeof(data));
  440. data[0] = 0;
  441. RegSetValueExA(hkey,
  442. "DllPatch-y",
  443. NULL,
  444. REG_SZ,
  445. data,
  446. 2);
  447. }
  448. }
  449. RegCloseKey(hkey);
  450. //
  451. // Finally, set a separate vdm flag
  452. // if we are here, it means that we are running under the layer
  453. // and the next exe is going to be shimmed.
  454. //
  455. *lpdwCreationFlags &= ~CREATE_SHARED_WOW_VDM;
  456. *lpdwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  457. return TRUE;
  458. }
  459. LPVOID
  460. ShimCreateWowEnvironment_U(
  461. LPVOID lpEnvironment, // pointer to the existing environment
  462. DWORD* lpdwFlags, // process creation flags
  463. BOOL bNewEnvironment // when set, forces us to clone environment ptr
  464. )
  465. {
  466. WOWENVDATA WowEnvData = { 0 };
  467. LPVOID lpEnvRet = lpEnvironment;
  468. LPVOID lpEnvCurrent = NULL;
  469. NTSTATUS Status = STATUS_SUCCESS;
  470. DWORD dwFlags = *lpdwFlags;
  471. UNICODE_STRING ustrProcessHistory = { 0 };
  472. ANSI_STRING strProcessHistory = { 0 };
  473. DWORD dwProcessHistoryLength = 0;
  474. UNICODE_STRING ustrCompatLayer = { 0 };
  475. ANSI_STRING strCompatLayer = { 0 };
  476. if (!ShimRetrieveVariablesEx(&WowEnvData)) {
  477. //
  478. // If no data, we have failed. Return the current data.
  479. //
  480. goto Fail;
  481. }
  482. if (bNewEnvironment) {
  483. Status = ShimCloneEnvironment(&lpEnvCurrent,
  484. lpEnvironment,
  485. !!(dwFlags & CREATE_UNICODE_ENVIRONMENT));
  486. if (!NT_SUCCESS(Status)) {
  487. LOGN(
  488. eDbgLevelError,
  489. "[ShimCreateWowEnvironment_U] Failed to clone the environment. Status = 0x%x",
  490. Status);
  491. goto Fail;
  492. }
  493. } else {
  494. lpEnvCurrent = lpEnvironment;
  495. }
  496. //
  497. // Now we are ready to set the environment in place.
  498. //
  499. //
  500. // Nuke the existing process history first. We don't care for the return result.
  501. //
  502. RtlSetEnvironmentVariable(&lpEnvCurrent, &g_ustrProcessHistoryVar, NULL);
  503. if (WowEnvData.pszProcessHistory != NULL ||
  504. WowEnvData.pszCurrentProcessHistory != NULL) {
  505. //
  506. // Convert the process history which consists of 2 strings.
  507. //
  508. // The length is the existing process history length + 1 (for ';') +
  509. // new process history length + 1 (for '\0')
  510. //
  511. dwProcessHistoryLength = ((WowEnvData.pszProcessHistory == NULL) ? 0 : (strlen(WowEnvData.pszProcessHistory) + 1)) +
  512. ((WowEnvData.pszCurrentProcessHistory == NULL) ? 0 : strlen(WowEnvData.pszCurrentProcessHistory)) + 1;
  513. //
  514. // Allocate process history buffer and convert it, allocating resulting unicode string.
  515. //
  516. strProcessHistory.Buffer = (PCHAR)ShimMalloc(dwProcessHistoryLength);
  517. if (strProcessHistory.Buffer == NULL) {
  518. LOGN(
  519. eDbgLevelError,
  520. "[ShimCreateWowEnvironment_U] failed to allocate %d bytes for process history.",
  521. dwProcessHistoryLength);
  522. Status = STATUS_NO_MEMORY;
  523. goto Fail;
  524. }
  525. strProcessHistory.MaximumLength = (USHORT)dwProcessHistoryLength;
  526. if (WowEnvData.pszProcessHistory != NULL) {
  527. // This StringCpy won't fail because strProcessHistory.Buffer has been allocated to the proper length.
  528. StringCchCopyA(strProcessHistory.Buffer, dwProcessHistoryLength, WowEnvData.pszProcessHistory);
  529. strProcessHistory.Length = strlen(WowEnvData.pszProcessHistory);
  530. } else {
  531. strProcessHistory.Length = 0;
  532. }
  533. if (WowEnvData.pszCurrentProcessHistory != NULL) {
  534. //
  535. // Append ';' if the string was not empty.
  536. //
  537. if (strProcessHistory.Length) {
  538. Status = RtlAppendAsciizToString(&strProcessHistory, ";");
  539. if (!NT_SUCCESS(Status)) {
  540. LOGN(
  541. eDbgLevelError,
  542. "[ShimCreateWowEnvironment_U] failed to append ';' to the process history. Status = 0x%x",
  543. Status);
  544. goto Fail;
  545. }
  546. }
  547. Status = RtlAppendAsciizToString(&strProcessHistory,
  548. WowEnvData.pszCurrentProcessHistory);
  549. if (!NT_SUCCESS(Status)) {
  550. LOGN(
  551. eDbgLevelError,
  552. "[ShimCreateWowEnvironment_U] failed to build the process history. Status = 0x%x",
  553. Status);
  554. goto Fail;
  555. }
  556. }
  557. //
  558. // Convert the process history.
  559. //
  560. Status = RtlAnsiStringToUnicodeString(&ustrProcessHistory, &strProcessHistory, TRUE);
  561. if (!NT_SUCCESS(Status)) {
  562. LOGN(
  563. eDbgLevelError,
  564. "[ShimCreateWowEnvironment_U] failed to convert process history to UNICODE. Status = 0x%x",
  565. Status);
  566. goto Fail;
  567. }
  568. //
  569. // Now we can set the process history.
  570. //
  571. Status = RtlSetEnvironmentVariable(&lpEnvCurrent,
  572. &g_ustrProcessHistoryVar,
  573. &ustrProcessHistory);
  574. if (!NT_SUCCESS(Status)) {
  575. LOGN(
  576. eDbgLevelError,
  577. "[ShimCreateWowEnvironment_U] failed to set the process history. Status = 0x%x",
  578. Status);
  579. goto Fail;
  580. }
  581. }
  582. //
  583. // Now we pass along any compat layer that we might have.
  584. //
  585. if (g_pwszCompatLayer != NULL) {
  586. //
  587. // Pass along this thing, we have been started under layer.
  588. //
  589. LOGN(
  590. eDbgLevelInfo,
  591. "[ShimCreateWowEnvironment_U] Propagating CompatLayer from the ntvdm environment __COMPAT_LAYER=\"%S\"",
  592. g_pwszCompatLayer);
  593. RtlInitUnicodeString(&ustrCompatLayer, g_pwszCompatLayer);
  594. Status = RtlSetEnvironmentVariable(&lpEnvCurrent, &g_ustrCompatLayerVar, &ustrCompatLayer);
  595. if (!NT_SUCCESS(Status)) {
  596. LOGN(
  597. eDbgLevelError,
  598. "[ShimCreateWowEnvironment_U] Failed to set compatlayer environment variable. Status = 0x%x",
  599. Status);
  600. goto Fail;
  601. }
  602. } else if (WowEnvData.pszCompatLayerVal != NULL) {
  603. LOGN(
  604. eDbgLevelInfo,
  605. "[ShimCreateWowEnvironment_U] Propagating CompatLayer from the parent WOW app \"%s\"",
  606. WowEnvData.pszCompatLayer);
  607. RtlInitString(&strCompatLayer, WowEnvData.pszCompatLayerVal);
  608. Status = RtlAnsiStringToUnicodeString(&ustrCompatLayer, &strCompatLayer, TRUE);
  609. if (!NT_SUCCESS(Status)) {
  610. LOGN(
  611. eDbgLevelError,
  612. "[ShimCreateWowEnvironment_U] Failed to convert compatlayer to UNICODE. Status = 0x%x",
  613. Status);
  614. goto Fail;
  615. }
  616. Status = RtlSetEnvironmentVariable(&lpEnvCurrent, &g_ustrCompatLayerVar, &ustrCompatLayer);
  617. RtlFreeUnicodeString(&ustrCompatLayer);
  618. if (!NT_SUCCESS(Status)) {
  619. LOGN(
  620. eDbgLevelError,
  621. "[ShimCreateWowEnvironment_U] Failed to set compatlayer environment variable. Status = 0x%x",
  622. Status);
  623. goto Fail;
  624. }
  625. }
  626. //
  627. // We have been successful. The return environment is UNICODE now.
  628. //
  629. lpEnvRet = (LPVOID)lpEnvCurrent;
  630. *lpdwFlags = dwFlags | CREATE_UNICODE_ENVIRONMENT;
  631. Status = STATUS_SUCCESS;
  632. Fail:
  633. if (!NT_SUCCESS(Status) && lpEnvCurrent != NULL && bNewEnvironment) {
  634. //
  635. // This points to the cloned environment ALWAYS.
  636. //
  637. RtlDestroyEnvironment(lpEnvCurrent);
  638. }
  639. RtlFreeUnicodeString(&ustrProcessHistory);
  640. if (strProcessHistory.Buffer != NULL) {
  641. ShimFree(strProcessHistory.Buffer);
  642. }
  643. //
  644. // This call is only necessary when using ShimRetrieveVariables.
  645. // It is not needed when using ShimRetrieveVariablesEx.
  646. //
  647. // ShimFreeWOWEnvData(&WowEnvData);
  648. //
  649. return lpEnvRet;
  650. }
  651. ULONG
  652. Win2kPropagateLayerExceptionHandler(
  653. PEXCEPTION_POINTERS pexi,
  654. char* szFile,
  655. DWORD dwLine
  656. )
  657. {
  658. LOGN(
  659. eDbgLevelError,
  660. "[Win2kPropagateLayerExceptionHandler] %#x in module \"%s\", line %d,"
  661. " at address %#p. flags:%#x. !exr %#p !cxr %#p",
  662. pexi->ExceptionRecord->ExceptionCode,
  663. szFile,
  664. dwLine,
  665. CONTEXT_TO_PROGRAM_COUNTER(pexi->ContextRecord),
  666. pexi->ExceptionRecord->ExceptionFlags,
  667. pexi->ExceptionRecord,
  668. pexi->ContextRecord);
  669. #if DBG
  670. DbgBreakPoint();
  671. #endif // DBG
  672. return EXCEPTION_EXECUTE_HANDLER;
  673. }
  674. /*++
  675. Stub functions that are intercepted from WOW initialization code
  676. (through APIHook_UserRegisterWowHandlers)
  677. --*/
  678. NSWOWUSERP::PFNINITTASK g_pfnInitTask;
  679. NSWOWUSERP::PFNWOWCLEANUP g_pfnWowCleanup;
  680. BOOL WINAPI
  681. StubInitTask(
  682. UINT dwExpWinVer,
  683. DWORD dwAppCompatFlags,
  684. LPCSTR lpszModName,
  685. LPCSTR lpszBaseFileName,
  686. DWORD hTaskWow,
  687. DWORD dwHotkey,
  688. DWORD idTask,
  689. DWORD dwX,
  690. DWORD dwY,
  691. DWORD dwXSize,
  692. DWORD dwYSize
  693. )
  694. {
  695. BOOL bReturn;
  696. bReturn = g_pfnInitTask(dwExpWinVer,
  697. dwAppCompatFlags,
  698. lpszModName,
  699. lpszBaseFileName,
  700. hTaskWow,
  701. dwHotkey,
  702. idTask,
  703. dwX,
  704. dwY,
  705. dwXSize,
  706. dwYSize);
  707. if (bReturn) {
  708. CheckAndShimNTVDM((WORD)hTaskWow);
  709. UpdateWowTaskList((WORD)hTaskWow);
  710. }
  711. return bReturn;
  712. }
  713. BOOL WINAPI
  714. StubWowCleanup(
  715. HANDLE hInstance,
  716. DWORD hTaskWow
  717. )
  718. {
  719. BOOL bReturn;
  720. bReturn = g_pfnWowCleanup(hInstance, hTaskWow);
  721. if (bReturn) {
  722. CleanupWowTaskList((WORD)hTaskWow);
  723. }
  724. return bReturn;
  725. }
  726. /*++
  727. APIHook_UserRegisterWowHandlers
  728. Trap InitTask and WowCleanup functions and
  729. replace them with stubs
  730. --*/
  731. ULONG_PTR
  732. APIHOOK(UserRegisterWowHandlers)(
  733. NSWOWUSERP::APFNWOWHANDLERSIN apfnWowIn,
  734. NSWOWUSERP::APFNWOWHANDLERSOUT apfnWowOut
  735. )
  736. {
  737. ULONG_PTR ulRet;
  738. ulRet = ORIGINAL_API(UserRegisterWowHandlers)(apfnWowIn, apfnWowOut);
  739. g_pfnInitTask = apfnWowOut->pfnInitTask;
  740. apfnWowOut->pfnInitTask = StubInitTask;
  741. g_pfnWowCleanup = apfnWowOut->pfnWOWCleanup;
  742. apfnWowOut->pfnWOWCleanup = StubWowCleanup;
  743. return ulRet;
  744. }
  745. BOOL
  746. CheckWOWExe(
  747. LPCWSTR lpApplicationName,
  748. LPVOID lpEnvironment,
  749. LPDWORD lpdwCreationFlags
  750. )
  751. {
  752. BOOL bSuccess;
  753. BOOL bReturn = FALSE;
  754. NTSTATUS Status;
  755. LPVOID pEnvironmentNew = lpEnvironment;
  756. SDBQUERYRESULT QueryResult;
  757. DWORD dwBinaryType = 0;
  758. HSDB hSDB = NULL;
  759. DWORD dwExes;
  760. WCHAR wszAppName[MAX_PATH];
  761. bSuccess = GetFileNameFromCmdLine(wszAppName, CHARCOUNT(wszAppName), lpApplicationName);
  762. if (!bSuccess) {
  763. return FALSE;
  764. }
  765. bSuccess = GetBinaryTypeW(wszAppName, &dwBinaryType);
  766. if (!bSuccess || dwBinaryType != SCS_WOW_BINARY) {
  767. LOGN( eDbgLevelInfo, "[CheckWowExe] can't get binary type\n");
  768. return FALSE;
  769. }
  770. //
  771. // for these binaries we shall perform the good deed of running the detection
  772. //
  773. hSDB = SdbInitDatabase(0, NULL);
  774. if (hSDB == NULL) {
  775. LOGN( eDbgLevelError, "[CheckWowExe] Failed to init the database.");
  776. return FALSE;
  777. }
  778. if (lpEnvironment != NULL && !(*lpdwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) { // non-null unicode env?
  779. Status = ShimCloneEnvironment(&pEnvironmentNew,
  780. lpEnvironment,
  781. FALSE);
  782. if (!NT_SUCCESS(Status)) {
  783. LOGN( eDbgLevelError, "[ShimCloneEnvironment] failed with status 0x%lx\n", Status);
  784. goto cleanup;
  785. }
  786. }
  787. //
  788. // all parameters below have to be unicode
  789. //
  790. dwExes = SdbGetMatchingExe(hSDB,
  791. wszAppName,
  792. NULL,
  793. (LPCWSTR)pEnvironmentNew,
  794. 0,
  795. &QueryResult);
  796. bSuccess = (QueryResult.atrExes [0] != TAGREF_NULL ||
  797. QueryResult.atrLayers[0] != TAGREF_NULL);
  798. //
  799. // if we have been successful -- layers apply to this thing
  800. //
  801. if (!bSuccess) {
  802. goto cleanup;
  803. }
  804. //
  805. // set the separate ntvdm flag and be on our way out
  806. //
  807. *lpdwCreationFlags &= ~CREATE_SHARED_WOW_VDM;
  808. *lpdwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  809. bReturn = TRUE;
  810. cleanup:
  811. if (pEnvironmentNew != lpEnvironment) {
  812. ShimFreeEnvironment(pEnvironmentNew);
  813. }
  814. if (hSDB) {
  815. SdbReleaseDatabase(hSDB);
  816. }
  817. return bReturn;
  818. }
  819. BOOL
  820. APIHOOK(CreateProcessA)(
  821. LPCSTR lpApplicationName,
  822. LPSTR lpCommandLine,
  823. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  824. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  825. BOOL bInheritHandles,
  826. DWORD dwCreationFlags,
  827. LPVOID lpEnvironment,
  828. LPCSTR lpCurrentDirectory,
  829. LPSTARTUPINFOA lpStartupInfo,
  830. LPPROCESS_INFORMATION lpProcessInformation
  831. )
  832. {
  833. BOOL bRet;
  834. LPVOID lpEnvironmentNew = lpEnvironment;
  835. LPSTR pszApp = NULL;
  836. LOGN(
  837. eDbgLevelError,
  838. "[CreateProcessA] called for:");
  839. LOGN(
  840. eDbgLevelError,
  841. "[CreateProcessA] lpApplicationName : \"%s\"",
  842. (lpApplicationName == NULL ? "null": lpApplicationName));
  843. LOGN(
  844. eDbgLevelError,
  845. "[CreateProcessA] lpCommandLine : \"%s\"",
  846. (lpCommandLine == NULL ? "null": lpCommandLine));
  847. if (lpApplicationName != NULL) {
  848. pszApp = (LPSTR)lpApplicationName;
  849. } else if (lpCommandLine != NULL) {
  850. pszApp = lpCommandLine;
  851. } else {
  852. LOGN(
  853. eDbgLevelError,
  854. "[CreateProcessA] called with NULL params.");
  855. }
  856. __try {
  857. WCHAR wszApp[MAX_PATH];
  858. if (pszApp != NULL) {
  859. if( MultiByteToWideChar(CP_ACP,
  860. 0,
  861. pszApp,
  862. -1,
  863. wszApp,
  864. MAX_PATH) )
  865. {
  866. AddSupport(wszApp, &lpEnvironmentNew, &dwCreationFlags);
  867. }
  868. }
  869. if (g_bIsNTVDM) {
  870. //
  871. // if the environment stayed the same as it was passed in -- clone it to propagate process history
  872. // if it was modified in AddSupport -- use it
  873. //
  874. lpEnvironmentNew = ShimCreateWowEnvironment_U(lpEnvironmentNew,
  875. &dwCreationFlags,
  876. lpEnvironmentNew == lpEnvironment);
  877. }
  878. if (pszApp != NULL && !(dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) {
  879. // since the separate vdm flag is not set -- we need to determine whether we have
  880. // any kind of fixes to care about.
  881. CheckWOWExe(wszApp, lpEnvironmentNew, &dwCreationFlags);
  882. }
  883. } __except(WOWPROCESSHISTORYEXCEPTIONFILTER) {
  884. //
  885. // cleanup the mess, if we have allocated the environment, free it now
  886. //
  887. if (lpEnvironmentNew != lpEnvironment) {
  888. ShimFreeEnvironment(lpEnvironmentNew);
  889. lpEnvironmentNew = lpEnvironment;
  890. }
  891. }
  892. bRet = ORIGINAL_API(CreateProcessA)(lpApplicationName,
  893. lpCommandLine,
  894. lpProcessAttributes,
  895. lpThreadAttributes,
  896. bInheritHandles,
  897. dwCreationFlags,
  898. lpEnvironmentNew,
  899. lpCurrentDirectory,
  900. lpStartupInfo,
  901. lpProcessInformation);
  902. if (lpEnvironmentNew != lpEnvironment) {
  903. //
  904. // The function below does not need a __try/__except wrapper, it has it internally
  905. //
  906. ShimFreeEnvironment(lpEnvironmentNew);
  907. }
  908. return bRet;
  909. }
  910. BOOL
  911. APIHOOK(CreateProcessW)(
  912. LPCWSTR lpApplicationName,
  913. LPWSTR lpCommandLine,
  914. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  915. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  916. BOOL bInheritHandles,
  917. DWORD dwCreationFlags,
  918. LPVOID lpEnvironment,
  919. LPCWSTR lpCurrentDirectory,
  920. LPSTARTUPINFOW lpStartupInfo,
  921. LPPROCESS_INFORMATION lpProcessInformation
  922. )
  923. {
  924. LPWSTR pszApp = NULL;
  925. BOOL bRet;
  926. LPVOID lpEnvironmentNew = lpEnvironment;
  927. LOGN(
  928. eDbgLevelInfo,
  929. "[CreateProcessW] called for:");
  930. LOGN(
  931. eDbgLevelInfo,
  932. "[CreateProcessW] lpApplicationName : \"%S\"",
  933. (lpApplicationName == NULL ? L"null": lpApplicationName));
  934. LOGN(
  935. eDbgLevelInfo,
  936. "[CreateProcessW] lpCommandLine : \"%S\"",
  937. (lpCommandLine == NULL ? L"null": lpCommandLine));
  938. if (lpApplicationName != NULL) {
  939. pszApp = (LPWSTR)lpApplicationName;
  940. } else if (lpCommandLine != NULL) {
  941. pszApp = lpCommandLine;
  942. } else {
  943. LOGN(
  944. eDbgLevelError,
  945. "[CreateProcessW] called with NULL params.");
  946. }
  947. __try {
  948. if (pszApp != NULL) {
  949. AddSupport(pszApp, &lpEnvironmentNew, &dwCreationFlags);
  950. }
  951. if (g_bIsNTVDM) {
  952. lpEnvironmentNew = ShimCreateWowEnvironment_U(lpEnvironmentNew,
  953. &dwCreationFlags,
  954. lpEnvironment == lpEnvironmentNew);
  955. }
  956. //
  957. // typically we need to find out whether the current app is ntvdm
  958. //
  959. if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) {
  960. // since the separate vdm flag is not set -- we need to determine whether we have
  961. // any kind of fixes to care about.
  962. CheckWOWExe(pszApp, lpEnvironmentNew, &dwCreationFlags);
  963. }
  964. } __except(WOWPROCESSHISTORYEXCEPTIONFILTER) {
  965. if (lpEnvironmentNew != lpEnvironment) {
  966. ShimFreeEnvironment(lpEnvironmentNew);
  967. lpEnvironmentNew = lpEnvironment; // reset the pointer
  968. }
  969. }
  970. bRet = ORIGINAL_API(CreateProcessW)(lpApplicationName,
  971. lpCommandLine,
  972. lpProcessAttributes,
  973. lpThreadAttributes,
  974. bInheritHandles,
  975. dwCreationFlags,
  976. lpEnvironmentNew,
  977. lpCurrentDirectory,
  978. lpStartupInfo,
  979. lpProcessInformation);
  980. if (lpEnvironmentNew != lpEnvironment) {
  981. ShimFreeEnvironment(lpEnvironmentNew);
  982. }
  983. return bRet;
  984. }
  985. BOOL
  986. GetVariableFromEnvironment(
  987. LPCWSTR pwszVariableName,
  988. LPWSTR* ppwszVariableValue
  989. )
  990. {
  991. DWORD dwLength;
  992. DWORD dwLen;
  993. BOOL bSuccess = FALSE;
  994. LPWSTR pwszVariableValue = *ppwszVariableValue;
  995. dwLength = GetEnvironmentVariableW(pwszVariableName, NULL, 0);
  996. if (dwLength == 0) {
  997. LOGN(
  998. eDbgLevelInfo,
  999. "[GetCompatLayerFromEnvironment] Not under the compatibility layer.");
  1000. *ppwszVariableValue = NULL;
  1001. return FALSE;
  1002. }
  1003. if (pwszVariableValue != NULL) {
  1004. LOGN(
  1005. eDbgLevelError,
  1006. "[GetCompatLayerFromEnvironment] called twice!");
  1007. ShimFree(pwszVariableValue);
  1008. pwszVariableValue = NULL;
  1009. }
  1010. pwszVariableValue = (WCHAR*)ShimMalloc(dwLength * sizeof(WCHAR));
  1011. if (pwszVariableValue == NULL) {
  1012. LOGN(
  1013. eDbgLevelError,
  1014. "[GetCompatLayerFromEnvironment] Failed to allocate %d bytes for Compat Layer.",
  1015. dwLength * sizeof(WCHAR));
  1016. goto out;
  1017. }
  1018. *pwszVariableValue = L'\0';
  1019. dwLen = GetEnvironmentVariableW(pwszVariableName,
  1020. pwszVariableValue,
  1021. dwLength);
  1022. bSuccess = (dwLen != 0 && dwLen < dwLength);
  1023. if (!bSuccess) {
  1024. LOGN(
  1025. eDbgLevelError,
  1026. "[GetCompatLayerFromEnvironment] Failed to get compat layer variable.");
  1027. ShimFree(pwszVariableValue);
  1028. pwszVariableValue = NULL;
  1029. }
  1030. out:
  1031. *ppwszVariableValue = pwszVariableValue;
  1032. return bSuccess;
  1033. }
  1034. BOOL
  1035. GetCompatLayerFromEnvironment(
  1036. VOID
  1037. )
  1038. {
  1039. return GetVariableFromEnvironment(g_wszCompatLayerVar, &g_pwszCompatLayer);
  1040. }
  1041. BOOL
  1042. GetSeparateWowPtr(
  1043. VOID
  1044. )
  1045. {
  1046. HMODULE hMod = GetModuleHandle(NULL);
  1047. g_pSeparateWow = (BOOL*)GetProcAddress(hMod, "fSeparateWow");
  1048. if (g_pSeparateWow == NULL) {
  1049. LOGN( eDbgLevelError, "[GetSeparateWowPtr] Failed 0x%lx\n", GetLastError());
  1050. return FALSE;
  1051. }
  1052. return TRUE;
  1053. }
  1054. VOID
  1055. ParseCommandLine(
  1056. LPCSTR commandLine
  1057. )
  1058. {
  1059. int i;
  1060. char* pArg;
  1061. g_argc = 0;
  1062. g_argv = NULL;
  1063. g_bIsNTVDM = FALSE;
  1064. g_bIsExplorer = FALSE;
  1065. g_argv = _CommandLineToArgvA(commandLine, &g_argc);
  1066. if (0 == g_argc || NULL == g_argv) {
  1067. return; // nothing to do
  1068. }
  1069. for (i = 0; i < g_argc; ++i) {
  1070. pArg = g_argv[i];
  1071. if (!_strcmpi(pArg, "ntvdm")) {
  1072. LOGN( eDbgLevelInfo, "[ParseCommandLine] Running NTVDM.");
  1073. g_bIsNTVDM = TRUE;
  1074. } else if (!_strcmpi(pArg, "explorer")) {
  1075. LOGN( eDbgLevelInfo, "[ParseCommandLine] Running Explorer.");
  1076. g_bIsExplorer = TRUE;
  1077. } else {
  1078. LOGN(
  1079. eDbgLevelError,
  1080. "[ParseCommandLine] Unrecognized argument: \"%s\"",
  1081. pArg);
  1082. }
  1083. }
  1084. if (g_bIsNTVDM && g_bIsExplorer) {
  1085. LOGN(
  1086. eDbgLevelError,
  1087. "[ParseCommandLine] Conflicting arguments! Neither will be applied.");
  1088. g_bIsNTVDM = FALSE;
  1089. g_bIsExplorer = FALSE;
  1090. }
  1091. }
  1092. BOOL
  1093. NOTIFY_FUNCTION(
  1094. DWORD fdwReason
  1095. )
  1096. {
  1097. OSVERSIONINFO osvi;
  1098. BOOL bHook = FALSE;
  1099. if (fdwReason != DLL_PROCESS_ATTACH) {
  1100. return TRUE;
  1101. }
  1102. osvi.dwOSVersionInfoSize = sizeof(osvi);
  1103. GetVersionEx(&osvi);
  1104. if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
  1105. ParseCommandLine(COMMAND_LINE);
  1106. if( InitLayerStorage(FALSE) ) {
  1107. CleanupRegistryForCurrentExe();
  1108. if (g_bIsNTVDM) {
  1109. bHook = TRUE;
  1110. //
  1111. // Retrieve the compat layer variable that we have been started with (just in case)
  1112. //
  1113. GetCompatLayerFromEnvironment();
  1114. GetSeparateWowPtr(); // retrieve ptr to a sep flag
  1115. } else if (g_bIsExplorer) {
  1116. //
  1117. // Cleanup compat layer variable
  1118. //
  1119. SetEnvironmentVariableW(g_wszCompatLayerVar, NULL);
  1120. bHook = TRUE;
  1121. } else {
  1122. //
  1123. // Neither explorer nor ntvdm. Get the compat layer.
  1124. //
  1125. bHook = GetCompatLayerFromEnvironment();
  1126. if (!bHook) {
  1127. LOGN(
  1128. eDbgLevelInfo,
  1129. "[NOTIFY_FUNCTION] Not under the compatibility layer.");
  1130. }
  1131. }
  1132. }
  1133. }
  1134. if (bHook) {
  1135. APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessA)
  1136. APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessW)
  1137. APIHOOK_ENTRY(USER32.DLL, UserRegisterWowHandlers)
  1138. }
  1139. return TRUE;
  1140. }
  1141. HOOK_BEGIN
  1142. CALL_NOTIFY_FUNCTION
  1143. HOOK_END
  1144. IMPLEMENT_SHIM_END