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.

869 lines
23 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * WKMAN.C
  8. * WOW32 16-bit Kernel API support (manually-coded thunks)
  9. *
  10. * History:
  11. * Created 16-Apr-2001 jarbats
  12. *
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*
  17. * shimdb has ..,.. which conflicts with the typedef TAG used in winuserp.h
  18. * so we redfine it here and put all the code which uses shimdb interfaces
  19. * in this file.
  20. *
  21. */
  22. #ifdef TAG
  23. #undef TAG
  24. #endif
  25. #define TAG _SHIMDB_WORDTAG
  26. #include "shimdb.h"
  27. #include "nt.h"
  28. #include "ntrtl.h"
  29. #include "nturtl.h"
  30. #include "zwapi.h"
  31. #define _wshimdb
  32. #include "wshimdb.h"
  33. MODNAME(wshimdb.c);
  34. CHAR g_szCompatLayerVar[] = "__COMPAT_LAYER";
  35. CHAR g_szProcessHistoryVar[] = "__PROCESS_HISTORY";
  36. CHAR g_szShimFileLogVar[] = "SHIM_FILE_LOG";
  37. UNICODE_STRING g_ustrProcessHistoryVar = RTL_CONSTANT_STRING(L"__PROCESS_HISTORY");
  38. UNICODE_STRING g_ustrCompatLayerVar = RTL_CONSTANT_STRING(L"__COMPAT_LAYER" );
  39. UNICODE_STRING g_ustrShimFileLogVar = RTL_CONSTANT_STRING(L"SHIM_FILE_LOG" );
  40. BOOL CheckAppHelpInfo(PTD pTD,PSZ szFileName,PSZ szModName) {
  41. BOOL fReturn = TRUE;
  42. NTVDM_FLAGS NtVdmFlags = { 0 };
  43. WCHAR wszFileName[256];
  44. WCHAR wszModName[16];
  45. WCHAR *pwszTempEnv = NULL;
  46. PSZ pszEnvTemplate = NULL;
  47. PWOWENVDATA pWowEnvData = NULL;
  48. PTD pTDParent = NULL;
  49. WCHAR wszCompatLayer[COMPATLAYERMAXLEN];
  50. APPHELP_INFO AHInfo;
  51. HANDLE hProcess;
  52. ghTaskAppHelp = NULL;
  53. RtlOemToUnicodeN(
  54. wszFileName,
  55. sizeof(wszFileName),
  56. NULL,
  57. szFileName,
  58. strlen(szFileName) + 1
  59. );
  60. RtlOemToUnicodeN(
  61. wszModName,
  62. sizeof(wszModName),
  63. NULL,
  64. szModName,
  65. strlen(szModName) + 1
  66. );
  67. //
  68. // find parent TD -- it contains the environment we need to
  69. // pass into the detection routine plus wowdata
  70. //
  71. pTDParent = GetParentTD(pTD->htask16);
  72. if (NULL != pTDParent) {
  73. pWowEnvData = pTDParent->pWowEnvDataChild;
  74. }
  75. pszEnvTemplate = GetTaskEnvptr(pTD->htask16);
  76. pwszTempEnv = WOWForgeUnicodeEnvironment(pszEnvTemplate, pWowEnvData) ;
  77. wszCompatLayer[0] = UNICODE_NULL;
  78. AHInfo.tiExe = 0;
  79. fReturn = ApphelpGetNTVDMInfo(wszFileName,
  80. wszModName,
  81. pwszTempEnv,
  82. wszCompatLayer,
  83. &NtVdmFlags,
  84. &AHInfo);
  85. if (pwszTempEnv != NULL) {
  86. WOWFreeUnicodeEnvironment(pwszTempEnv);
  87. }
  88. if (fReturn && AHInfo.tiExe) {
  89. fReturn = ApphelpShowDialog(&AHInfo,&hProcess);
  90. if (fReturn && hProcess) {
  91. ghTaskAppHelp = hProcess;
  92. }
  93. }
  94. WOWInheritEnvironment(pTD, pTDParent, wszCompatLayer, szFileName);
  95. pTD->dwWOWCompatFlags = NtVdmFlags.dwWOWCompatFlags;
  96. pTD->dwWOWCompatFlagsEx = NtVdmFlags.dwWOWCompatFlagsEx;
  97. pTD->dwUserWOWCompatFlags = NtVdmFlags.dwUserWOWCompatFlags;
  98. pTD->dwWOWCompatFlags2 = NtVdmFlags.dwWOWCompatFlags2;
  99. #ifdef FE_SB
  100. pTD->dwWOWCompatFlagsFE = NtVdmFlags.dwWOWCompatFlagsFE;
  101. #endif // FE_SB
  102. // Clean up starts here
  103. return fReturn;
  104. }
  105. ///////////////////////////////////////////////////////////////////////////////////////////////////
  106. //
  107. //
  108. // Welcome to Win2kPropagateLayer which manages everything in the environment
  109. // related to shims/detection
  110. //
  111. //
  112. // this function is called during the parent tasks pass_environment call
  113. // we are still in the context of the parent, which means that:
  114. // CURRENTPTD() gives us parents' TD
  115. // *pCurTDB gives us parents' TDB
  116. //
  117. //
  118. // get the pointer to task database block from hTask
  119. //
  120. PTDB
  121. GetTDB(
  122. HAND16 hTask
  123. )
  124. {
  125. PTDB pTDB;
  126. pTDB = (PTDB)SEGPTR(hTask, 0);
  127. if (NULL == pTDB || TDB_SIGNATURE != pTDB->TDB_sig) {
  128. return NULL;
  129. }
  130. return pTDB;
  131. }
  132. PSZ
  133. GetTaskEnvptr(
  134. HAND16 hTask
  135. )
  136. {
  137. PTDB pTDB = GetTDB(hTask);
  138. PSZ pszEnv = NULL;
  139. PDOSPDB pPSP;
  140. if (NULL == pTDB) {
  141. return NULL;
  142. }
  143. //
  144. // Prepare environment data - this buffer is used when we're starting a new task from the
  145. // root of the chain (as opposed to spawning from an existing 16-bit task)
  146. //
  147. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  148. if (pPSP != NULL) {
  149. pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0);
  150. }
  151. return pszEnv;
  152. }
  153. PTD
  154. GetParentTD(
  155. HAND16 hTask
  156. )
  157. {
  158. PTDB pTDB = GetTDB(hTask);
  159. PTDB pTDBParent;
  160. PTD ptdCur = NULL;
  161. HAND16 hTaskParent;
  162. if (NULL == pTDB) {
  163. return NULL; // cannot get that task
  164. }
  165. //
  166. // now, retrieve the TD for the parent.
  167. //
  168. hTaskParent = pTDB->TDB_Parent;
  169. pTDBParent = GetTDB(hTaskParent);
  170. if (NULL == pTDBParent) {
  171. // can's see the parent
  172. return NULL;
  173. }
  174. //
  175. // so we can see what the parent is up to
  176. //
  177. // pTDBParent->TDB_ThreadID and
  178. // hTaskParent are the dead giveaway
  179. //
  180. ptdCur = gptdTaskHead;
  181. while (NULL != ptdCur) {
  182. if (ptdCur->dwThreadID == pTDBParent->TDB_ThreadID &&
  183. ptdCur->htask16 == hTaskParent) {
  184. break;
  185. }
  186. ptdCur = ptdCur->ptdNext;
  187. }
  188. //
  189. // if ptdCur == NULL -- we have not been able to locate the parent tasks' ptd
  190. //
  191. return ptdCur;
  192. }
  193. BOOL
  194. IsWowExec(
  195. WORD wTask
  196. )
  197. {
  198. return (ghShellTDB == wTask);
  199. }
  200. //
  201. // This function is called in the context of pass_environment
  202. //
  203. //
  204. //
  205. BOOL
  206. CreateWowChildEnvInformation(
  207. PSZ pszEnvParent
  208. )
  209. {
  210. PTD pTD; // parent TD
  211. WOWENVDATA EnvData;
  212. PWOWENVDATA pData = NULL;
  213. PWOWENVDATA pEnvChildData = NULL;
  214. DWORD dwLength;
  215. PCH pBuffer;
  216. RtlZeroMemory(&EnvData, sizeof(EnvData));
  217. //
  218. // check where we should inherit process history and layers from
  219. //
  220. pTD = CURRENTPTD();
  221. if (pTD->pWowEnvDataChild) {
  222. free_w(pTD->pWowEnvDataChild);
  223. pTD->pWowEnvDataChild = NULL;
  224. }
  225. //
  226. // check whether we are starting the root task (meaning that this task IS wowexec)
  227. // if so, we shall inherit things from pParamBlk->envseg
  228. // else we use TD of the parent task (this TD that is) to
  229. // inherit things
  230. // How to detect that this is wowexec:
  231. // ghShellTDB could we compared to *pCurTDB
  232. // gptdShell->hTask16 could be compared to *pCurTDB
  233. // we check for not having wowexec -- if gptdShell == NULL then we're doing boot
  234. //
  235. if (pCurTDB == NULL || IsWowExec(*pCurTDB)) {
  236. //
  237. // presumably we are wowexec
  238. // use current environment ptr to get stuff (like pParamBlk->envseg)
  239. // or the original ntvdm environment
  240. //
  241. pData = &EnvData;
  242. pData->pszProcessHistory = WOWFindEnvironmentVar(g_szProcessHistoryVar,
  243. pszEnvParent,
  244. &pData->pszProcessHistoryVal);
  245. pData->pszCompatLayer = WOWFindEnvironmentVar(g_szCompatLayerVar,
  246. pszEnvParent,
  247. &pData->pszCompatLayerVal);
  248. pData->pszShimFileLog = WOWFindEnvironmentVar(g_szShimFileLogVar,
  249. pszEnvParent,
  250. &pData->pszShimFileLogVal);
  251. } else {
  252. //
  253. // this current task is not a dastardly wowexec
  254. // clone current + enhance process history
  255. //
  256. pData = pTD->pWowEnvData; // if this is NULL
  257. if (pData == NULL) {
  258. pData = &EnvData; // all the vars are empty
  259. }
  260. }
  261. //
  262. //
  263. //
  264. //
  265. dwLength = sizeof(WOWENVDATA) +
  266. (NULL == pData->pszProcessHistory ? 0 : (strlen(pData->pszProcessHistory) + 1) * sizeof(CHAR)) +
  267. (NULL == pData->pszCompatLayer ? 0 : (strlen(pData->pszCompatLayer) + 1) * sizeof(CHAR)) +
  268. (NULL == pData->pszShimFileLog ? 0 : (strlen(pData->pszShimFileLog) + 1) * sizeof(CHAR)) +
  269. (NULL == pData->pszCurrentProcessHistory ? 0 : (strlen(pData->pszCurrentProcessHistory) + 1) * sizeof(CHAR));
  270. pEnvChildData = (PWOWENVDATA)malloc_w(dwLength);
  271. if (pEnvChildData == NULL) {
  272. return FALSE;
  273. }
  274. RtlZeroMemory(pEnvChildData, dwLength);
  275. //
  276. // now this entry has to be setup
  277. // process history is first
  278. //
  279. pBuffer = (PCH)(pEnvChildData + 1);
  280. if (pData->pszProcessHistory != NULL) {
  281. //
  282. // Copy process history. The processHistoryVal is a pointer into the buffer
  283. // pointed to by pszProcessHistory: __PROCESS_HISTORY=c:\foo;c:\docs~1\install
  284. // then pszProcessHistoryVal will point here ---------^
  285. //
  286. // we are copying the data and moving the pointer using the calculated offset
  287. pEnvChildData->pszProcessHistory = pBuffer;
  288. strcpy(pEnvChildData->pszProcessHistory, pData->pszProcessHistory);
  289. pEnvChildData->pszProcessHistoryVal = pEnvChildData->pszProcessHistory +
  290. (INT)(pData->pszProcessHistoryVal - pData->pszProcessHistory);
  291. //
  292. // There is enough space in the buffer to accomodate all the strings, so
  293. // move pointer past current string to point at the "empty" space
  294. //
  295. pBuffer += strlen(pData->pszProcessHistory) + 1;
  296. }
  297. if (pData->pszCompatLayer != NULL) {
  298. pEnvChildData->pszCompatLayer = pBuffer;
  299. strcpy(pEnvChildData->pszCompatLayer, pData->pszCompatLayer);
  300. pEnvChildData->pszCompatLayerVal = pEnvChildData->pszCompatLayer +
  301. (INT)(pData->pszCompatLayerVal - pData->pszCompatLayer);
  302. pBuffer += strlen(pData->pszCompatLayer) + 1;
  303. }
  304. if (pData->pszShimFileLog != NULL) {
  305. pEnvChildData->pszShimFileLog = pBuffer;
  306. strcpy(pEnvChildData->pszShimFileLog, pData->pszShimFileLog);
  307. pEnvChildData->pszShimFileLogVal = pEnvChildData->pszShimFileLog +
  308. (INT)(pData->pszShimFileLogVal - pData->pszShimFileLog);
  309. pBuffer += strlen(pData->pszShimFileLog) + 1;
  310. }
  311. if (pData->pszCurrentProcessHistory != NULL) {
  312. //
  313. // Now process history
  314. //
  315. pEnvChildData->pszCurrentProcessHistory = pBuffer;
  316. if (pData->pszCurrentProcessHistory != NULL) {
  317. strcpy(pEnvChildData->pszCurrentProcessHistory, pData->pszCurrentProcessHistory);
  318. }
  319. }
  320. //
  321. // we are done, environment cloned
  322. //
  323. pTD->pWowEnvDataChild = pEnvChildData;
  324. return TRUE;
  325. }
  326. //
  327. // In : pointer to environment(oem)
  328. // out: pointer to unicode environment
  329. //
  330. NTSTATUS
  331. WOWCloneEnvironment(
  332. LPVOID* ppEnvOut,
  333. PSZ lpEnvironment
  334. )
  335. {
  336. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  337. DWORD dwEnvSize = 0;
  338. LPVOID lpEnvNew = NULL;
  339. MEMORY_BASIC_INFORMATION MemoryInformation;
  340. if (NULL == lpEnvironment) {
  341. Status = RtlCreateEnvironment(TRUE, &lpEnvNew);
  342. } else {
  343. dwEnvSize = WOWGetEnvironmentSize(lpEnvironment, NULL);
  344. MemoryInformation.RegionSize = (dwEnvSize + 2) * sizeof(UNICODE_NULL);
  345. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  346. &lpEnvNew,
  347. 0,
  348. &MemoryInformation.RegionSize,
  349. MEM_COMMIT,
  350. PAGE_READWRITE);
  351. }
  352. if (NULL != lpEnvironment) {
  353. UNICODE_STRING UnicodeBuffer;
  354. OEM_STRING OemBuffer;
  355. OemBuffer.Buffer = (CHAR*)lpEnvironment;
  356. OemBuffer.Length = OemBuffer.MaximumLength = (USHORT)dwEnvSize; // size in bytes = size in chars, includes \0\0
  357. UnicodeBuffer.Buffer = (WCHAR*)lpEnvNew;
  358. UnicodeBuffer.Length = (USHORT)dwEnvSize * sizeof(UNICODE_NULL);
  359. UnicodeBuffer.MaximumLength = (USHORT)(dwEnvSize + 2) * sizeof(UNICODE_NULL); // leave room for \0
  360. Status = RtlOemStringToUnicodeString(&UnicodeBuffer, &OemBuffer, FALSE);
  361. }
  362. if (NT_SUCCESS(Status)) {
  363. *ppEnvOut = lpEnvNew;
  364. } else {
  365. if (NULL != lpEnvNew) {
  366. RtlDestroyEnvironment(lpEnvNew);
  367. }
  368. }
  369. return Status;
  370. }
  371. NTSTATUS
  372. WOWFreeUnicodeEnvironment(
  373. LPVOID lpEnvironment
  374. )
  375. {
  376. NTSTATUS Status;
  377. Status = RtlDestroyEnvironment(lpEnvironment);
  378. return Status;
  379. }
  380. //
  381. // Set environment variable, possibly create or clone provided environment
  382. //
  383. NTSTATUS
  384. WOWSetEnvironmentVar_U(
  385. LPVOID* ppEnvironment,
  386. WCHAR* pwszVarName,
  387. WCHAR* pwszVarValue
  388. )
  389. {
  390. UNICODE_STRING ustrVarName;
  391. UNICODE_STRING ustrVarValue;
  392. NTSTATUS Status;
  393. RtlInitUnicodeString(&ustrVarName, pwszVarName);
  394. if (NULL != pwszVarValue) {
  395. RtlInitUnicodeString(&ustrVarValue, pwszVarValue);
  396. }
  397. Status = RtlSetEnvironmentVariable(ppEnvironment,
  398. &ustrVarName,
  399. (NULL == pwszVarValue) ? NULL : &ustrVarValue);
  400. return Status;
  401. }
  402. NTSTATUS
  403. WOWSetEnvironmentVar_Oem(
  404. LPVOID* ppEnvironment,
  405. PUNICODE_STRING pustrVarName, // pre-made (cheap)
  406. PSZ pszVarValue
  407. )
  408. {
  409. OEM_STRING OemString = { 0 };
  410. UNICODE_STRING ustrVarValue = { 0 };
  411. NTSTATUS Status;
  412. if (pszVarValue != NULL) {
  413. RtlInitString(&OemString, pszVarValue);
  414. Status = RtlOemStringToUnicodeString(&ustrVarValue, &OemString, TRUE);
  415. if (!NT_SUCCESS(Status)) {
  416. return Status;
  417. }
  418. }
  419. Status = RtlSetEnvironmentVariable(ppEnvironment,
  420. pustrVarName,
  421. (NULL == pszVarValue) ? NULL : &ustrVarValue);
  422. if (NULL != pszVarValue) {
  423. RtlFreeUnicodeString(&ustrVarValue);
  424. }
  425. return Status;
  426. }
  427. //
  428. // Call this function to produce a "good" unicode environment
  429. //
  430. //
  431. LPWSTR
  432. WOWForgeUnicodeEnvironment(
  433. PSZ pEnvironment, // this task's sanitized environment
  434. PWOWENVDATA pEnvData // parent-made environment data
  435. )
  436. {
  437. NTSTATUS Status;
  438. LPVOID lpEnvNew = NULL;
  439. DWORD dwProcessHistoryLength = 0;
  440. PSZ pszFullProcessHistory = NULL;
  441. Status = WOWCloneEnvironment(&lpEnvNew, pEnvironment);
  442. if (!NT_SUCCESS(Status)) {
  443. return NULL;
  444. }
  445. //
  446. // we do have an env to work with
  447. //
  448. RtlSetEnvironmentVariable(&lpEnvNew, &g_ustrProcessHistoryVar, NULL);
  449. RtlSetEnvironmentVariable(&lpEnvNew, &g_ustrCompatLayerVar, NULL);
  450. RtlSetEnvironmentVariable(&lpEnvNew, &g_ustrShimFileLogVar, NULL);
  451. //
  452. // get stuff from envdata
  453. //
  454. if (pEnvData == NULL) {
  455. goto Done;
  456. }
  457. if (pEnvData->pszProcessHistory != NULL || pEnvData->pszCurrentProcessHistory != NULL) {
  458. //
  459. // Convert the process history which consists of 2 strings.
  460. //
  461. // The length is the existing process history length + 1 (for ';') +
  462. // new process history length + 1 (for '\0')
  463. //
  464. dwProcessHistoryLength = ((pEnvData->pszProcessHistory == NULL) ? 0 : (strlen(pEnvData->pszProcessHistoryVal) + 1)) +
  465. ((pEnvData->pszCurrentProcessHistory == NULL) ? 0 : strlen(pEnvData->pszCurrentProcessHistory)) + 1;
  466. //
  467. // Allocate process history buffer and convert it, allocating resulting unicode string.
  468. //
  469. pszFullProcessHistory = (PCHAR)malloc_w(dwProcessHistoryLength);
  470. if (NULL == pszFullProcessHistory) {
  471. Status = STATUS_NO_MEMORY;
  472. goto Done;
  473. }
  474. *pszFullProcessHistory = '\0';
  475. if (pEnvData->pszProcessHistory != NULL) {
  476. strcpy(pszFullProcessHistory, pEnvData->pszProcessHistoryVal);
  477. }
  478. if (pEnvData->pszCurrentProcessHistory != NULL) {
  479. //
  480. // Append ';' if the string was not empty.
  481. //
  482. if (*pszFullProcessHistory) {
  483. strcat(pszFullProcessHistory, ";");
  484. }
  485. strcat(pszFullProcessHistory, pEnvData->pszCurrentProcessHistory);
  486. }
  487. Status = WOWSetEnvironmentVar_Oem(&lpEnvNew,
  488. &g_ustrProcessHistoryVar,
  489. pszFullProcessHistory);
  490. if (!NT_SUCCESS(Status)) {
  491. goto Done;
  492. }
  493. }
  494. //
  495. // deal with compatLayer
  496. //
  497. if (pEnvData->pszCompatLayerVal != NULL) {
  498. Status = WOWSetEnvironmentVar_Oem(&lpEnvNew,
  499. &g_ustrCompatLayerVar,
  500. pEnvData->pszCompatLayerVal);
  501. if (!NT_SUCCESS(Status)) {
  502. goto Done;
  503. }
  504. }
  505. if (pEnvData->pszShimFileLog != NULL) {
  506. Status = WOWSetEnvironmentVar_Oem(&lpEnvNew,
  507. &g_ustrShimFileLogVar,
  508. pEnvData->pszShimFileLogVal);
  509. if (!NT_SUCCESS(Status)) {
  510. goto Done;
  511. }
  512. }
  513. Done:
  514. if (pszFullProcessHistory != NULL) {
  515. free_w(pszFullProcessHistory);
  516. }
  517. if (!NT_SUCCESS(Status) && lpEnvNew != NULL) {
  518. //
  519. // This points to the cloned environment ALWAYS.
  520. //
  521. RtlDestroyEnvironment(lpEnvNew);
  522. lpEnvNew = NULL;
  523. }
  524. return(LPWSTR)lpEnvNew;
  525. }
  526. //
  527. // GetModName
  528. // wTDB - TDB entry
  529. // szModName - pointer to the buffer that receives module name
  530. // buffer should be at least 9 characters long
  531. //
  532. // returns FALSE if the entry is invalid
  533. BOOL
  534. GetWOWModName(
  535. WORD wTDB,
  536. PCH szModName
  537. )
  538. {
  539. PTDB pTDB;
  540. PCH pch;
  541. pTDB = GetTDB(wTDB);
  542. if (NULL == pTDB) {
  543. return FALSE;
  544. }
  545. RtlCopyMemory(szModName, pTDB->TDB_ModName, 8 * sizeof(CHAR)); // we have modname now
  546. szModName[8] = '\0';
  547. pch = &szModName[8];
  548. while (*(--pch) == ' ') {
  549. *pch = 0;
  550. }
  551. return TRUE;
  552. }
  553. // IsWowExec
  554. // IN wTDB - entry into the task database
  555. // Returns:
  556. // TRUE if this particular entry points to WOWEXEC
  557. //
  558. // Note:
  559. // WOWEXEC is a special stub module that always runs on NTVDM
  560. // new tasks are spawned by wowexec (in the most typical case)
  561. // it is therefore the "root" module and it's environment's contents
  562. // should not be counted, since we don't know what was ntvdm's parent process
  563. //
  564. BOOL
  565. IsWOWExecBoot(
  566. WORD wTDB
  567. )
  568. {
  569. PTDB pTDB;
  570. CHAR szModName[9];
  571. pTDB = GetTDB(wTDB);
  572. if (NULL == pTDB) {
  573. return FALSE;
  574. }
  575. if (!GetWOWModName(wTDB, szModName)) { // can we get modname ?
  576. return FALSE;
  577. }
  578. return (0 == _strcmpi(szModName, "wowexec")); // is the module named WOWEXEC ?
  579. }
  580. BOOL
  581. WOWInheritEnvironment(
  582. PTD pTD, // this TD
  583. PTD pTDParent, // parent TD
  584. LPCWSTR pwszLayers, // new layers var
  585. LPCSTR pszFileName // exe filename
  586. )
  587. {
  588. UNICODE_STRING ustrLayers = { 0 };
  589. OEM_STRING oemLayers = { 0 };
  590. PWOWENVDATA pEnvData = NULL;
  591. PWOWENVDATA pEnvDataParent = NULL;
  592. DWORD dwLength = sizeof(WOWENVDATA);
  593. BOOL bSuccess = FALSE;
  594. PCH pBuffer;
  595. // assert (pszFileName != NULL)
  596. // check if this is dreaded wowexec
  597. if (IsWOWExecBoot(pTD->htask16)) {
  598. return TRUE;
  599. }
  600. if (NULL != pwszLayers) {
  601. RtlInitUnicodeString(&ustrLayers, pwszLayers);
  602. RtlUnicodeStringToOemString(&oemLayers, &ustrLayers, TRUE);
  603. }
  604. if (pTDParent != NULL) {
  605. pEnvDataParent = pTDParent->pWowEnvDataChild; // from parent, created for our consumption
  606. }
  607. //
  608. // inherit process history (normal that is)
  609. //
  610. if (pEnvDataParent != NULL) {
  611. dwLength += pEnvDataParent->pszProcessHistory == NULL ? 0 : strlen(pEnvDataParent->pszProcessHistory) + 1;
  612. dwLength += pEnvDataParent->pszShimFileLog == NULL ? 0 : strlen(pEnvDataParent->pszShimFileLog) + 1;
  613. dwLength += pEnvDataParent->pszCurrentProcessHistory == NULL ? 0 : strlen(pEnvDataParent->pszCurrentProcessHistory) + 1;
  614. }
  615. dwLength += oemLayers.Length != 0 ? oemLayers.Length + 1 + strlen(g_szCompatLayerVar) + 1 : 0; // length for layers
  616. dwLength += strlen(pszFileName) + 1;
  617. //
  618. // now all components are done, allocate
  619. //
  620. pEnvData = (PWOWENVDATA)malloc_w(dwLength);
  621. if (pEnvData == NULL) {
  622. goto out;
  623. }
  624. RtlZeroMemory(pEnvData, dwLength);
  625. pBuffer = (PCH)(pEnvData + 1);
  626. if (pEnvDataParent != NULL) {
  627. if (pEnvDataParent->pszProcessHistory) {
  628. pEnvData->pszProcessHistory = pBuffer;
  629. strcpy(pBuffer, pEnvDataParent->pszProcessHistory);
  630. pEnvData->pszProcessHistoryVal = pEnvData->pszProcessHistory +
  631. (INT)(pEnvDataParent->pszProcessHistoryVal - pEnvDataParent->pszProcessHistory);
  632. pBuffer += strlen(pBuffer) + 1;
  633. }
  634. if (pEnvDataParent->pszShimFileLog) {
  635. pEnvData->pszShimFileLog = pBuffer;
  636. strcpy(pBuffer, pEnvDataParent->pszShimFileLog);
  637. pEnvData->pszShimFileLogVal = pEnvData->pszShimFileLog +
  638. (INT)(pEnvDataParent->pszShimFileLogVal - pEnvDataParent->pszShimFileLog);
  639. pBuffer += strlen(pBuffer) + 1;
  640. }
  641. }
  642. if (oemLayers.Length) {
  643. pEnvData->pszCompatLayer = pBuffer;
  644. strcpy(pBuffer, g_szCompatLayerVar); // __COMPAT_LAYER
  645. strcat(pBuffer, "=");
  646. pEnvData->pszCompatLayerVal = pBuffer + strlen(pBuffer);
  647. strcpy(pEnvData->pszCompatLayerVal, oemLayers.Buffer);
  648. pBuffer += strlen(pBuffer) + 1;
  649. }
  650. //
  651. // Process History HAS to be the last item
  652. //
  653. pEnvData->pszCurrentProcessHistory = pBuffer;
  654. *pBuffer = '\0';
  655. if (pEnvDataParent != NULL) {
  656. if (pEnvDataParent->pszCurrentProcessHistory) {
  657. pEnvData->pszCurrentProcessHistory = pBuffer;
  658. strcat(pBuffer, pEnvDataParent->pszCurrentProcessHistory);
  659. strcat(pBuffer, ";");
  660. }
  661. }
  662. strcat(pEnvData->pszCurrentProcessHistory, pszFileName);
  663. bSuccess = TRUE;
  664. out:
  665. RtlFreeOemString(&oemLayers);
  666. pTD->pWowEnvData = pEnvData;
  667. return bSuccess;
  668. }