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.

1087 lines
31 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. MODNAME(wshimdb.c);
  33. CHAR g_szCompatLayerVar[] = "__COMPAT_LAYER";
  34. CHAR g_szProcessHistoryVar[] = "__PROCESS_HISTORY";
  35. CHAR g_szShimFileLogVar[] = "SHIM_FILE_LOG";
  36. extern PFAMILY_TABLE *pgDpmWowFamTbls;
  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. HSDB hSdb = NULL;
  52. SDBQUERYRESULT SdbQuery;
  53. HANDLE hProcess;
  54. ghTaskAppHelp = NULL;
  55. RtlOemToUnicodeN(
  56. wszFileName,
  57. sizeof(wszFileName),
  58. NULL,
  59. szFileName,
  60. strlen(szFileName) + 1
  61. );
  62. RtlOemToUnicodeN(
  63. wszModName,
  64. sizeof(wszModName),
  65. NULL,
  66. szModName,
  67. strlen(szModName) + 1
  68. );
  69. //
  70. // find parent TD -- it contains the environment we need to
  71. // pass into the detection routine plus wowdata
  72. //
  73. pTDParent = GetParentTD(pTD->htask16);
  74. if (NULL != pTDParent) {
  75. pWowEnvData = pTDParent->pWowEnvDataChild;
  76. }
  77. pszEnvTemplate = GetTaskEnvptr(pTD->htask16);
  78. pwszTempEnv = WOWForgeUnicodeEnvironment(pszEnvTemplate, pWowEnvData) ;
  79. wszCompatLayer[0] = UNICODE_NULL;
  80. AHInfo.tiExe = 0;
  81. fReturn = ApphelpGetNTVDMInfo(wszFileName,
  82. wszModName,
  83. pwszTempEnv,
  84. wszCompatLayer,
  85. &NtVdmFlags,
  86. &AHInfo,
  87. &hSdb,
  88. &SdbQuery);
  89. if(fReturn) {
  90. if (AHInfo.tiExe &&
  91. ApphelpShowDialog(&AHInfo,&hProcess) &&
  92. hProcess) {
  93. ghTaskAppHelp = hProcess;
  94. }
  95. if(AHInfo.dwSeverity == APPHELP_HARDBLOCK) {
  96. fReturn = FALSE;
  97. goto ExitCAHI;
  98. }
  99. }
  100. WOWInheritEnvironment(pTD, pTDParent, wszCompatLayer, szFileName);
  101. pTD->dwWOWCompatFlags = NtVdmFlags.dwWOWCompatFlags;
  102. pTD->dwWOWCompatFlagsEx = NtVdmFlags.dwWOWCompatFlagsEx;
  103. pTD->dwUserWOWCompatFlags = NtVdmFlags.dwUserWOWCompatFlags;
  104. pTD->dwWOWCompatFlags2 = NtVdmFlags.dwWOWCompatFlags2;
  105. #ifdef FE_SB
  106. pTD->dwWOWCompatFlagsFE = NtVdmFlags.dwWOWCompatFlagsFE;
  107. #endif // FE_SB
  108. pTD->pWOWCompatFlagsEx_Info = InitFlagInfo(NtVdmFlags.pFlagsInfo, WOWCOMPATFLAGSEX,NtVdmFlags.dwWOWCompatFlagsEx);
  109. pTD->pWOWCompatFlags2_Info = InitFlagInfo(NtVdmFlags.pFlagsInfo, WOWCOMPATFLAGS2,NtVdmFlags.dwWOWCompatFlags2);
  110. // if the app requires Dynamic Patch Module(s) and/or shims to be linked
  111. if(NtVdmFlags.dwWOWCompatFlags2 & WOWCF2_DPM_PATCHES) {
  112. CMDLNPARMS CmdLnParms;
  113. PFLAGINFOBITS pFlagInfoBits;
  114. pFlagInfoBits = CheckFlagInfo(WOWCOMPATFLAGS2, WOWCF2_DPM_PATCHES);
  115. if(pFlagInfoBits) {
  116. CmdLnParms.argc = (int)pFlagInfoBits->dwFlagArgc;
  117. CmdLnParms.argv = (char **)pFlagInfoBits->pFlagArgv;
  118. CmdLnParms.dwFlag = WOWCF2_DPM_PATCHES;
  119. InitTaskDpmSupport(NUM_WOW_FAMILIES_HOOKED,
  120. pgDpmWowFamTbls,
  121. &CmdLnParms,
  122. (PVOID)hSdb,
  123. (PVOID)&SdbQuery,
  124. wszFileName,
  125. wszModName,
  126. pwszTempEnv);
  127. }
  128. }
  129. ExitCAHI:
  130. if (pwszTempEnv != NULL) {
  131. WOWFreeUnicodeEnvironment(pwszTempEnv);
  132. }
  133. if (hSdb != NULL) {
  134. SdbReleaseDatabase(hSdb);
  135. }
  136. SdbFreeFlagInfo(NtVdmFlags.pFlagsInfo);
  137. // Clean up starts here
  138. return fReturn;
  139. }
  140. ///////////////////////////////////////////////////////////////////////////////////////////////////
  141. //
  142. //
  143. // Welcome to Win2kPropagateLayer which manages everything in the environment
  144. // related to shims/detection
  145. //
  146. //
  147. // this function is called during the parent tasks pass_environment call
  148. // we are still in the context of the parent, which means that:
  149. // CURRENTPTD() gives us parents' TD
  150. // *pCurTDB gives us parents' TDB
  151. //
  152. //
  153. // get the pointer to task database block from hTask
  154. //
  155. PTDB
  156. GetTDB(
  157. HAND16 hTask
  158. )
  159. {
  160. PTDB pTDB;
  161. pTDB = (PTDB)SEGPTR(hTask, 0);
  162. if (NULL == pTDB || TDB_SIGNATURE != pTDB->TDB_sig) {
  163. return NULL;
  164. }
  165. return pTDB;
  166. }
  167. PSZ
  168. GetTaskEnvptr(
  169. HAND16 hTask
  170. )
  171. {
  172. PTDB pTDB = GetTDB(hTask);
  173. PSZ pszEnv = NULL;
  174. PDOSPDB pPSP;
  175. if (NULL == pTDB) {
  176. return NULL;
  177. }
  178. //
  179. // Prepare environment data - this buffer is used when we're starting a new task from the
  180. // root of the chain (as opposed to spawning from an existing 16-bit task)
  181. //
  182. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  183. if (pPSP != NULL) {
  184. pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0);
  185. }
  186. return pszEnv;
  187. }
  188. PTD
  189. GetParentTD(
  190. HAND16 hTask
  191. )
  192. {
  193. PTDB pTDB = GetTDB(hTask);
  194. PTDB pTDBParent;
  195. PTD ptdCur = NULL;
  196. HAND16 hTaskParent;
  197. if (NULL == pTDB) {
  198. return NULL; // cannot get that task
  199. }
  200. //
  201. // now, retrieve the TD for the parent.
  202. //
  203. hTaskParent = pTDB->TDB_Parent;
  204. pTDBParent = GetTDB(hTaskParent);
  205. if (NULL == pTDBParent) {
  206. // can's see the parent
  207. return NULL;
  208. }
  209. //
  210. // so we can see what the parent is up to
  211. //
  212. // pTDBParent->TDB_ThreadID and
  213. // hTaskParent are the dead giveaway
  214. //
  215. ptdCur = gptdTaskHead;
  216. while (NULL != ptdCur) {
  217. if (ptdCur->dwThreadID == pTDBParent->TDB_ThreadID &&
  218. ptdCur->htask16 == hTaskParent) {
  219. break;
  220. }
  221. ptdCur = ptdCur->ptdNext;
  222. }
  223. //
  224. // if ptdCur == NULL -- we have not been able to locate the parent tasks' ptd
  225. //
  226. return ptdCur;
  227. }
  228. BOOL
  229. IsWowExec(
  230. WORD wTask
  231. )
  232. {
  233. return (ghShellTDB == wTask);
  234. }
  235. //
  236. // This function is called in the context of pass_environment
  237. //
  238. //
  239. //
  240. BOOL
  241. CreateWowChildEnvInformation(
  242. PSZ pszEnvParent
  243. )
  244. {
  245. PTD pTD; // parent TD
  246. WOWENVDATA EnvData;
  247. PWOWENVDATA pData = NULL;
  248. PWOWENVDATA pEnvChildData = NULL;
  249. DWORD dwLength;
  250. PCH pBuffer;
  251. RtlZeroMemory(&EnvData, sizeof(EnvData));
  252. //
  253. // check where we should inherit process history and layers from
  254. //
  255. pTD = CURRENTPTD();
  256. if (pTD->pWowEnvDataChild) {
  257. free_w(pTD->pWowEnvDataChild);
  258. pTD->pWowEnvDataChild = NULL;
  259. }
  260. //
  261. // check whether we are starting the root task (meaning that this task IS wowexec)
  262. // if so, we shall inherit things from pParamBlk->envseg
  263. // else we use TD of the parent task (this TD that is) to
  264. // inherit things
  265. // How to detect that this is wowexec:
  266. // ghShellTDB could we compared to *pCurTDB
  267. // gptdShell->hTask16 could be compared to *pCurTDB
  268. // we check for not having wowexec -- if gptdShell == NULL then we're doing boot
  269. //
  270. if (pCurTDB == NULL || IsWowExec(*pCurTDB)) {
  271. //
  272. // presumably we are wowexec
  273. // use current environment ptr to get stuff (like pParamBlk->envseg)
  274. // or the original ntvdm environment
  275. //
  276. pData = &EnvData;
  277. pData->pszProcessHistory = WOWFindEnvironmentVar(g_szProcessHistoryVar,
  278. pszEnvParent,
  279. &pData->pszProcessHistoryVal);
  280. pData->pszCompatLayer = WOWFindEnvironmentVar(g_szCompatLayerVar,
  281. pszEnvParent,
  282. &pData->pszCompatLayerVal);
  283. pData->pszShimFileLog = WOWFindEnvironmentVar(g_szShimFileLogVar,
  284. pszEnvParent,
  285. &pData->pszShimFileLogVal);
  286. } else {
  287. //
  288. // this current task is not a dastardly wowexec
  289. // clone current + enhance process history
  290. //
  291. pData = pTD->pWowEnvData; // if this is NULL
  292. if (pData == NULL) {
  293. pData = &EnvData; // all the vars are empty
  294. }
  295. }
  296. //
  297. //
  298. //
  299. //
  300. dwLength = sizeof(WOWENVDATA) +
  301. (NULL == pData->pszProcessHistory ? 0 : (strlen(pData->pszProcessHistory) + 1) * sizeof(CHAR)) +
  302. (NULL == pData->pszCompatLayer ? 0 : (strlen(pData->pszCompatLayer) + 1) * sizeof(CHAR)) +
  303. (NULL == pData->pszShimFileLog ? 0 : (strlen(pData->pszShimFileLog) + 1) * sizeof(CHAR)) +
  304. (NULL == pData->pszCurrentProcessHistory ? 0 : (strlen(pData->pszCurrentProcessHistory) + 1) * sizeof(CHAR));
  305. pEnvChildData = (PWOWENVDATA)malloc_w(dwLength);
  306. if (pEnvChildData == NULL) {
  307. return FALSE;
  308. }
  309. RtlZeroMemory(pEnvChildData, dwLength);
  310. //
  311. // now this entry has to be setup
  312. // process history is first
  313. //
  314. pBuffer = (PCH)(pEnvChildData + 1);
  315. if (pData->pszProcessHistory != NULL) {
  316. //
  317. // Copy process history. The processHistoryVal is a pointer into the buffer
  318. // pointed to by pszProcessHistory: __PROCESS_HISTORY=c:\foo;c:\docs~1\install
  319. // then pszProcessHistoryVal will point here ---------^
  320. //
  321. // we are copying the data and moving the pointer using the calculated offset
  322. pEnvChildData->pszProcessHistory = pBuffer;
  323. strcpy(pEnvChildData->pszProcessHistory, pData->pszProcessHistory);
  324. pEnvChildData->pszProcessHistoryVal = pEnvChildData->pszProcessHistory +
  325. (INT)(pData->pszProcessHistoryVal - pData->pszProcessHistory);
  326. //
  327. // There is enough space in the buffer to accomodate all the strings, so
  328. // move pointer past current string to point at the "empty" space
  329. //
  330. pBuffer += strlen(pData->pszProcessHistory) + 1;
  331. }
  332. if (pData->pszCompatLayer != NULL) {
  333. pEnvChildData->pszCompatLayer = pBuffer;
  334. strcpy(pEnvChildData->pszCompatLayer, pData->pszCompatLayer);
  335. pEnvChildData->pszCompatLayerVal = pEnvChildData->pszCompatLayer +
  336. (INT)(pData->pszCompatLayerVal - pData->pszCompatLayer);
  337. pBuffer += strlen(pData->pszCompatLayer) + 1;
  338. }
  339. if (pData->pszShimFileLog != NULL) {
  340. pEnvChildData->pszShimFileLog = pBuffer;
  341. strcpy(pEnvChildData->pszShimFileLog, pData->pszShimFileLog);
  342. pEnvChildData->pszShimFileLogVal = pEnvChildData->pszShimFileLog +
  343. (INT)(pData->pszShimFileLogVal - pData->pszShimFileLog);
  344. pBuffer += strlen(pData->pszShimFileLog) + 1;
  345. }
  346. if (pData->pszCurrentProcessHistory != NULL) {
  347. //
  348. // Now process history
  349. //
  350. pEnvChildData->pszCurrentProcessHistory = pBuffer;
  351. if (pData->pszCurrentProcessHistory != NULL) {
  352. strcpy(pEnvChildData->pszCurrentProcessHistory, pData->pszCurrentProcessHistory);
  353. }
  354. }
  355. //
  356. // we are done, environment cloned
  357. //
  358. pTD->pWowEnvDataChild = pEnvChildData;
  359. return TRUE;
  360. }
  361. //
  362. // In : pointer to environment(oem)
  363. // out: pointer to unicode environment
  364. //
  365. NTSTATUS
  366. WOWCloneEnvironment(
  367. LPVOID* ppEnvOut,
  368. PSZ lpEnvironment
  369. )
  370. {
  371. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  372. DWORD dwEnvSize = 0;
  373. LPVOID lpEnvNew = NULL;
  374. MEMORY_BASIC_INFORMATION MemoryInformation;
  375. if (NULL == lpEnvironment) {
  376. Status = RtlCreateEnvironment(TRUE, &lpEnvNew);
  377. } else {
  378. dwEnvSize = WOWGetEnvironmentSize(lpEnvironment, NULL);
  379. MemoryInformation.RegionSize = (dwEnvSize + 2) * sizeof(UNICODE_NULL);
  380. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  381. &lpEnvNew,
  382. 0,
  383. &MemoryInformation.RegionSize,
  384. MEM_COMMIT,
  385. PAGE_READWRITE);
  386. }
  387. if (NULL != lpEnvironment) {
  388. UNICODE_STRING UnicodeBuffer;
  389. OEM_STRING OemBuffer;
  390. OemBuffer.Buffer = (CHAR*)lpEnvironment;
  391. OemBuffer.Length = OemBuffer.MaximumLength = (USHORT)dwEnvSize; // size in bytes = size in chars, includes \0\0
  392. UnicodeBuffer.Buffer = (WCHAR*)lpEnvNew;
  393. UnicodeBuffer.Length = (USHORT)dwEnvSize * sizeof(UNICODE_NULL);
  394. UnicodeBuffer.MaximumLength = (USHORT)(dwEnvSize + 2) * sizeof(UNICODE_NULL); // leave room for \0
  395. Status = RtlOemStringToUnicodeString(&UnicodeBuffer, &OemBuffer, FALSE);
  396. }
  397. if (NT_SUCCESS(Status)) {
  398. *ppEnvOut = lpEnvNew;
  399. } else {
  400. if (NULL != lpEnvNew) {
  401. RtlDestroyEnvironment(lpEnvNew);
  402. }
  403. }
  404. return Status;
  405. }
  406. NTSTATUS
  407. WOWFreeUnicodeEnvironment(
  408. LPVOID lpEnvironment
  409. )
  410. {
  411. NTSTATUS Status;
  412. Status = RtlDestroyEnvironment(lpEnvironment);
  413. return Status;
  414. }
  415. //
  416. // Set environment variable, possibly create or clone provided environment
  417. //
  418. NTSTATUS
  419. WOWSetEnvironmentVar_U(
  420. LPVOID* ppEnvironment,
  421. WCHAR* pwszVarName,
  422. WCHAR* pwszVarValue
  423. )
  424. {
  425. UNICODE_STRING ustrVarName;
  426. UNICODE_STRING ustrVarValue;
  427. NTSTATUS Status;
  428. RtlInitUnicodeString(&ustrVarName, pwszVarName);
  429. if (NULL != pwszVarValue) {
  430. RtlInitUnicodeString(&ustrVarValue, pwszVarValue);
  431. }
  432. Status = RtlSetEnvironmentVariable(ppEnvironment,
  433. &ustrVarName,
  434. (NULL == pwszVarValue) ? NULL : &ustrVarValue);
  435. return Status;
  436. }
  437. NTSTATUS
  438. WOWSetEnvironmentVar_Oem(
  439. LPVOID* ppEnvironment,
  440. PUNICODE_STRING pustrVarName, // pre-made (cheap)
  441. PSZ pszVarValue
  442. )
  443. {
  444. OEM_STRING OemString = { 0 };
  445. UNICODE_STRING ustrVarValue = { 0 };
  446. NTSTATUS Status;
  447. if (pszVarValue != NULL) {
  448. RtlInitString(&OemString, pszVarValue);
  449. Status = RtlOemStringToUnicodeString(&ustrVarValue, &OemString, TRUE);
  450. if (!NT_SUCCESS(Status)) {
  451. return Status;
  452. }
  453. }
  454. Status = RtlSetEnvironmentVariable(ppEnvironment,
  455. pustrVarName,
  456. (NULL == pszVarValue) ? NULL : &ustrVarValue);
  457. if (NULL != pszVarValue) {
  458. RtlFreeUnicodeString(&ustrVarValue);
  459. }
  460. return Status;
  461. }
  462. //
  463. // Call this function to produce a "good" unicode environment
  464. //
  465. //
  466. LPWSTR
  467. WOWForgeUnicodeEnvironment(
  468. PSZ pEnvironment, // this task's sanitized environment
  469. PWOWENVDATA pEnvData // parent-made environment data
  470. )
  471. {
  472. NTSTATUS Status;
  473. LPVOID lpEnvNew = NULL;
  474. DWORD dwProcessHistoryLength = 0;
  475. PSZ pszFullProcessHistory = NULL;
  476. Status = WOWCloneEnvironment(&lpEnvNew, pEnvironment);
  477. if (!NT_SUCCESS(Status)) {
  478. return NULL;
  479. }
  480. //
  481. // we do have an env to work with
  482. //
  483. RtlSetEnvironmentVariable(&lpEnvNew, &g_ustrProcessHistoryVar, NULL);
  484. RtlSetEnvironmentVariable(&lpEnvNew, &g_ustrCompatLayerVar, NULL);
  485. RtlSetEnvironmentVariable(&lpEnvNew, &g_ustrShimFileLogVar, NULL);
  486. //
  487. // get stuff from envdata
  488. //
  489. if (pEnvData == NULL) {
  490. goto Done;
  491. }
  492. if (pEnvData->pszProcessHistory != NULL || pEnvData->pszCurrentProcessHistory != NULL) {
  493. //
  494. // Convert the process history which consists of 2 strings.
  495. //
  496. // The length is the existing process history length + 1 (for ';') +
  497. // new process history length + 1 (for '\0')
  498. //
  499. dwProcessHistoryLength = ((pEnvData->pszProcessHistory == NULL) ? 0 : (strlen(pEnvData->pszProcessHistoryVal) + 1)) +
  500. ((pEnvData->pszCurrentProcessHistory == NULL) ? 0 : strlen(pEnvData->pszCurrentProcessHistory)) + 1;
  501. //
  502. // Allocate process history buffer and convert it, allocating resulting unicode string.
  503. //
  504. pszFullProcessHistory = (PCHAR)malloc_w(dwProcessHistoryLength);
  505. if (NULL == pszFullProcessHistory) {
  506. Status = STATUS_NO_MEMORY;
  507. goto Done;
  508. }
  509. *pszFullProcessHistory = '\0';
  510. if (pEnvData->pszProcessHistory != NULL) {
  511. strcpy(pszFullProcessHistory, pEnvData->pszProcessHistoryVal);
  512. }
  513. if (pEnvData->pszCurrentProcessHistory != NULL) {
  514. //
  515. // Append ';' if the string was not empty.
  516. //
  517. if (*pszFullProcessHistory) {
  518. strcat(pszFullProcessHistory, ";");
  519. }
  520. strcat(pszFullProcessHistory, pEnvData->pszCurrentProcessHistory);
  521. }
  522. Status = WOWSetEnvironmentVar_Oem(&lpEnvNew,
  523. &g_ustrProcessHistoryVar,
  524. pszFullProcessHistory);
  525. if (!NT_SUCCESS(Status)) {
  526. goto Done;
  527. }
  528. }
  529. //
  530. // deal with compatLayer
  531. //
  532. if (pEnvData->pszCompatLayerVal != NULL) {
  533. Status = WOWSetEnvironmentVar_Oem(&lpEnvNew,
  534. &g_ustrCompatLayerVar,
  535. pEnvData->pszCompatLayerVal);
  536. if (!NT_SUCCESS(Status)) {
  537. goto Done;
  538. }
  539. }
  540. if (pEnvData->pszShimFileLog != NULL) {
  541. Status = WOWSetEnvironmentVar_Oem(&lpEnvNew,
  542. &g_ustrShimFileLogVar,
  543. pEnvData->pszShimFileLogVal);
  544. if (!NT_SUCCESS(Status)) {
  545. goto Done;
  546. }
  547. }
  548. Done:
  549. if (pszFullProcessHistory != NULL) {
  550. free_w(pszFullProcessHistory);
  551. }
  552. if (!NT_SUCCESS(Status) && lpEnvNew != NULL) {
  553. //
  554. // This points to the cloned environment ALWAYS.
  555. //
  556. RtlDestroyEnvironment(lpEnvNew);
  557. lpEnvNew = NULL;
  558. }
  559. return(LPWSTR)lpEnvNew;
  560. }
  561. //
  562. // GetModName
  563. // wTDB - TDB entry
  564. // szModName - pointer to the buffer that receives module name
  565. // buffer should be at least 9 characters long
  566. //
  567. // returns FALSE if the entry is invalid
  568. BOOL
  569. GetWOWModName(
  570. WORD wTDB,
  571. PCH szModName
  572. )
  573. {
  574. PTDB pTDB;
  575. PCH pch;
  576. pTDB = GetTDB(wTDB);
  577. if (NULL == pTDB) {
  578. return FALSE;
  579. }
  580. RtlCopyMemory(szModName, pTDB->TDB_ModName, 8 * sizeof(CHAR)); // we have modname now
  581. szModName[8] = '\0';
  582. pch = &szModName[8];
  583. while (*(--pch) == ' ') {
  584. *pch = 0;
  585. }
  586. return TRUE;
  587. }
  588. // IsWowExec
  589. // IN wTDB - entry into the task database
  590. // Returns:
  591. // TRUE if this particular entry points to WOWEXEC
  592. //
  593. // Note:
  594. // WOWEXEC is a special stub module that always runs on NTVDM
  595. // new tasks are spawned by wowexec (in the most typical case)
  596. // it is therefore the "root" module and it's environment's contents
  597. // should not be counted, since we don't know what was ntvdm's parent process
  598. //
  599. BOOL
  600. IsWOWExecBoot(
  601. WORD wTDB
  602. )
  603. {
  604. PTDB pTDB;
  605. CHAR szModName[9];
  606. pTDB = GetTDB(wTDB);
  607. if (NULL == pTDB) {
  608. return FALSE;
  609. }
  610. if (!GetWOWModName(wTDB, szModName)) { // can we get modname ?
  611. return FALSE;
  612. }
  613. return (0 == _strcmpi(szModName, "wowexec")); // is the module named WOWEXEC ?
  614. }
  615. BOOL
  616. WOWInheritEnvironment(
  617. PTD pTD, // this TD
  618. PTD pTDParent, // parent TD
  619. LPCWSTR pwszLayers, // new layers var
  620. LPCSTR pszFileName // exe filename
  621. )
  622. {
  623. UNICODE_STRING ustrLayers = { 0 };
  624. OEM_STRING oemLayers = { 0 };
  625. PWOWENVDATA pEnvData = NULL;
  626. PWOWENVDATA pEnvDataParent = NULL;
  627. DWORD dwLength = sizeof(WOWENVDATA);
  628. BOOL bSuccess = FALSE;
  629. PCH pBuffer;
  630. // assert (pszFileName != NULL)
  631. // check if this is dreaded wowexec
  632. if (IsWOWExecBoot(pTD->htask16)) {
  633. return TRUE;
  634. }
  635. if (NULL != pwszLayers) {
  636. RtlInitUnicodeString(&ustrLayers, pwszLayers);
  637. RtlUnicodeStringToOemString(&oemLayers, &ustrLayers, TRUE);
  638. }
  639. if (pTDParent != NULL) {
  640. pEnvDataParent = pTDParent->pWowEnvDataChild; // from parent, created for our consumption
  641. }
  642. //
  643. // inherit process history (normal that is)
  644. //
  645. if (pEnvDataParent != NULL) {
  646. dwLength += pEnvDataParent->pszProcessHistory == NULL ? 0 : strlen(pEnvDataParent->pszProcessHistory) + 1;
  647. dwLength += pEnvDataParent->pszShimFileLog == NULL ? 0 : strlen(pEnvDataParent->pszShimFileLog) + 1;
  648. dwLength += pEnvDataParent->pszCurrentProcessHistory == NULL ? 0 : strlen(pEnvDataParent->pszCurrentProcessHistory) + 1;
  649. }
  650. dwLength += oemLayers.Length != 0 ? oemLayers.Length + 1 + strlen(g_szCompatLayerVar) + 1 : 0; // length for layers
  651. dwLength += strlen(pszFileName) + 1;
  652. //
  653. // now all components are done, allocate
  654. //
  655. pEnvData = (PWOWENVDATA)malloc_w(dwLength);
  656. if (pEnvData == NULL) {
  657. goto out;
  658. }
  659. RtlZeroMemory(pEnvData, dwLength);
  660. pBuffer = (PCH)(pEnvData + 1);
  661. if (pEnvDataParent != NULL) {
  662. if (pEnvDataParent->pszProcessHistory) {
  663. pEnvData->pszProcessHistory = pBuffer;
  664. strcpy(pBuffer, pEnvDataParent->pszProcessHistory);
  665. pEnvData->pszProcessHistoryVal = pEnvData->pszProcessHistory +
  666. (INT)(pEnvDataParent->pszProcessHistoryVal - pEnvDataParent->pszProcessHistory);
  667. pBuffer += strlen(pBuffer) + 1;
  668. }
  669. if (pEnvDataParent->pszShimFileLog) {
  670. pEnvData->pszShimFileLog = pBuffer;
  671. strcpy(pBuffer, pEnvDataParent->pszShimFileLog);
  672. pEnvData->pszShimFileLogVal = pEnvData->pszShimFileLog +
  673. (INT)(pEnvDataParent->pszShimFileLogVal - pEnvDataParent->pszShimFileLog);
  674. pBuffer += strlen(pBuffer) + 1;
  675. }
  676. }
  677. if (oemLayers.Length) {
  678. pEnvData->pszCompatLayer = pBuffer;
  679. strcpy(pBuffer, g_szCompatLayerVar); // __COMPAT_LAYER
  680. strcat(pBuffer, "=");
  681. pEnvData->pszCompatLayerVal = pBuffer + strlen(pBuffer);
  682. strcpy(pEnvData->pszCompatLayerVal, oemLayers.Buffer);
  683. pBuffer += strlen(pBuffer) + 1;
  684. }
  685. //
  686. // Process History HAS to be the last item
  687. //
  688. pEnvData->pszCurrentProcessHistory = pBuffer;
  689. *pBuffer = '\0';
  690. if (pEnvDataParent != NULL) {
  691. if (pEnvDataParent->pszCurrentProcessHistory) {
  692. pEnvData->pszCurrentProcessHistory = pBuffer;
  693. strcat(pBuffer, pEnvDataParent->pszCurrentProcessHistory);
  694. strcat(pBuffer, ";");
  695. }
  696. }
  697. strcat(pEnvData->pszCurrentProcessHistory, pszFileName);
  698. bSuccess = TRUE;
  699. out:
  700. RtlFreeOemString(&oemLayers);
  701. pTD->pWowEnvData = pEnvData;
  702. return bSuccess;
  703. }
  704. PFLAGINFOBITS CheckFlagInfo(DWORD FlagType, DWORD dwFlag) {
  705. PFLAGINFOBITS pFlagInfoBits;
  706. switch(FlagType){
  707. case WOWCOMPATFLAGSEX:
  708. pFlagInfoBits = CURRENTPTD()->pWOWCompatFlagsEx_Info;
  709. break;
  710. case WOWCOMPATFLAGS2:
  711. pFlagInfoBits = CURRENTPTD()->pWOWCompatFlags2_Info;
  712. break;
  713. default:
  714. WOW32ASSERTMSG((FALSE), ("CheckFlagInfo called with invalid FlagType!"));
  715. return NULL;
  716. }
  717. while(pFlagInfoBits) {
  718. if(pFlagInfoBits->dwFlag == dwFlag) {
  719. return pFlagInfoBits;
  720. }
  721. pFlagInfoBits = pFlagInfoBits->pNextFlagInfoBits;
  722. }
  723. return NULL;
  724. }
  725. PFLAGINFOBITS InitFlagInfo(PVOID pFlagInfo,DWORD FlagType,DWORD dwFlag) {
  726. UNICODE_STRING uCmdLine = { 0 };
  727. OEM_STRING oemCmdLine = { 0 };
  728. LPWSTR lpwCmdLine;
  729. DWORD dwMark = 0x80000000;
  730. LPSTR pszTmp;
  731. PFLAGINFOBITS pFlagInfoBits,pFlagInfoBitsHead = NULL;
  732. LPSTR pszCmdLine;
  733. LPSTR *pFlagArgv;
  734. DWORD dwFlagArgc;
  735. if(pFlagInfo == NULL || 0 == dwFlag) {
  736. return NULL;
  737. }
  738. while(dwMark) {
  739. if(dwFlag & dwMark) {
  740. pFlagArgv = NULL;
  741. pszCmdLine = NULL;
  742. pFlagInfoBits = NULL;
  743. lpwCmdLine = NULL;
  744. switch(FlagType) {
  745. case WOWCOMPATFLAGSEX:
  746. GET_WOWCOMPATFLAGSEX_CMDLINE(pFlagInfo, dwMark, &lpwCmdLine);
  747. break;
  748. case WOWCOMPATFLAGS2:
  749. GET_WOWCOMPATFLAGS2_CMDLINE(pFlagInfo, dwMark, &lpwCmdLine);
  750. break;
  751. default:
  752. WOW32ASSERTMSG((FALSE), ("InitFlagInfo called with invalid FlagType!"));
  753. return NULL;
  754. }
  755. if(lpwCmdLine) {
  756. //
  757. // Convert to oem string
  758. //
  759. RtlInitUnicodeString(&uCmdLine, lpwCmdLine);
  760. pszCmdLine = malloc_w(uCmdLine.Length+1);
  761. if(NULL == pszCmdLine) {
  762. goto GFIerror;
  763. }
  764. oemCmdLine.Buffer = pszCmdLine;
  765. oemCmdLine.MaximumLength = uCmdLine.Length+1;
  766. RtlUnicodeStringToOemString(&oemCmdLine, &uCmdLine, FALSE);
  767. pFlagInfoBits = malloc_w(sizeof(FLAGINFOBITS));
  768. if(NULL == pFlagInfoBits) {
  769. goto GFIerror;
  770. }
  771. pFlagInfoBits->pNextFlagInfoBits = NULL;
  772. pFlagInfoBits->dwFlag = dwMark;
  773. pFlagInfoBits->dwFlagType = FlagType;
  774. pFlagInfoBits->pszCmdLine = pszCmdLine;
  775. //
  776. // Parse commandline to argv, argc format
  777. //
  778. dwFlagArgc = 1;
  779. pszTmp = pszCmdLine;
  780. while(*pszTmp) {
  781. if(*pszTmp == ';') {
  782. dwFlagArgc++;
  783. }
  784. pszTmp++;
  785. }
  786. pFlagInfoBits->dwFlagArgc = dwFlagArgc;
  787. pFlagArgv = malloc_w(sizeof(LPSTR)*dwFlagArgc);
  788. if (NULL == pFlagArgv) {
  789. goto GFIerror;
  790. }
  791. pFlagInfoBits->pFlagArgv = pFlagArgv;
  792. pszTmp = pszCmdLine;
  793. while(*pszTmp) {
  794. if(*pszTmp == ';'){
  795. if(pszCmdLine != pszTmp) {
  796. *pFlagArgv++ = pszCmdLine;
  797. }
  798. else {
  799. *pFlagArgv++ = NULL;
  800. }
  801. *pszTmp = '\0';
  802. pszCmdLine = pszTmp+1;
  803. }
  804. pszTmp++;
  805. }
  806. *pFlagArgv = pszCmdLine;
  807. if(pFlagInfoBitsHead) {
  808. pFlagInfoBits->pNextFlagInfoBits = pFlagInfoBitsHead;
  809. pFlagInfoBitsHead = pFlagInfoBits;
  810. }
  811. else {
  812. pFlagInfoBitsHead = pFlagInfoBits;
  813. }
  814. }
  815. }
  816. // Check next bit
  817. dwMark = dwMark>>1;
  818. }
  819. return pFlagInfoBitsHead;
  820. GFIerror:
  821. if (pszCmdLine) {
  822. free_w(pszCmdLine);
  823. }
  824. if (pFlagInfoBits) {
  825. free_w(pFlagInfoBits);
  826. }
  827. if (pFlagArgv) {
  828. free_w(pFlagArgv);
  829. }
  830. return pFlagInfoBitsHead;
  831. }
  832. VOID FreeFlagInfo(PFLAGINFOBITS pFlagInfoBits){
  833. PFLAGINFOBITS pFlagInfoBitsTmp;
  834. while(pFlagInfoBits) {
  835. pFlagInfoBitsTmp = pFlagInfoBits->pNextFlagInfoBits;
  836. if(pFlagInfoBits->pszCmdLine) {
  837. free_w(pFlagInfoBits->pszCmdLine);
  838. }
  839. if(pFlagInfoBits->pFlagArgv) {
  840. free_w(pFlagInfoBits->pFlagArgv);
  841. }
  842. free_w(pFlagInfoBits);
  843. pFlagInfoBits = pFlagInfoBitsTmp;
  844. }
  845. }