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.

1433 lines
38 KiB

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