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.

1004 lines
25 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. WoWTask.cpp
  5. Abstract:
  6. Functions that retrieve process-history related information from
  7. 16-bit environment. This includes the retrieval of the correct
  8. __PROCESS_HISTORY that was passed in from the parent (32-bit)process
  9. and tracing the process history through WOW
  10. Notes:
  11. History:
  12. 10/26/00 VadimB Created
  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. typedef struct tagFINDWOWTASKDATA {
  21. BOOL bFound;
  22. DWORD dwProcessId;
  23. DWORD dwThreadId;
  24. WORD hMod16;
  25. WORD hTask16;
  26. } FINDWOWTASKDATA, *PFINDWOWTASKDATA;
  27. //
  28. // Dynamically Linked apis
  29. //
  30. // from WOW32.dll
  31. //
  32. typedef LPVOID (WINAPI *PFNWOWGetVDMPointer)(DWORD vp,
  33. DWORD dwBytes,
  34. BOOL fProtectedMode);
  35. //
  36. // from vdmdbg.dll - defined in the header file
  37. //
  38. //
  39. typedef INT (WINAPI *PFNVDMEnumTaskWOW)(DWORD dwProcessId,
  40. TASKENUMPROC fp,
  41. LPARAM lparam);
  42. //
  43. // Api importing -- modules
  44. //
  45. WCHAR g_wszWOW32ModName[] = L"wow32.dll";
  46. WCHAR g_wszVdmDbgModName[] = L"VdmDbg.dll";
  47. //
  48. // Api importing - module handles and function pointers
  49. //
  50. HMODULE g_hWow32;
  51. HMODULE g_hVdmDbg;
  52. BOOL g_bInitialized; // set to true when imports are initialized
  53. PFNWOWGetVDMPointer g_pfnWOWGetVDMPointer;
  54. PFNVDMEnumTaskWOW g_pfnVDMEnumTaskWOW;
  55. extern BOOL* g_pSeparateWow;
  56. //
  57. // function in this module to import apis
  58. //
  59. BOOL ImportWowApis(VOID);
  60. //
  61. // Marcro to access 16-bit memory
  62. //
  63. #define SEGPTR(seg,off) ((g_pfnWOWGetVDMPointer)((((ULONG)seg) << 16) | (off), 0, TRUE))
  64. //
  65. // task enum proc, called back from vdmdbg
  66. //
  67. BOOL WINAPI MyTaskEnumProc(
  68. DWORD dwThreadId,
  69. WORD hMod16,
  70. WORD hTask16,
  71. LPARAM lParam
  72. )
  73. {
  74. PFINDWOWTASKDATA pFindData = (PFINDWOWTASKDATA)lParam;
  75. if (dwThreadId == pFindData->dwThreadId) {
  76. pFindData->hMod16 = hMod16;
  77. pFindData->hTask16 = hTask16;
  78. pFindData->bFound = TRUE;
  79. return TRUE;
  80. }
  81. return FALSE;
  82. }
  83. BOOL FindWowTask(
  84. DWORD dwProcessId,
  85. DWORD dwThreadId,
  86. PFINDWOWTASKDATA pFindData
  87. )
  88. {
  89. RtlZeroMemory(pFindData, sizeof(*pFindData));
  90. pFindData->dwProcessId = dwProcessId;
  91. pFindData->dwThreadId = dwThreadId;
  92. g_pfnVDMEnumTaskWOW(dwProcessId, (TASKENUMPROC)MyTaskEnumProc, (LPARAM)pFindData);
  93. return pFindData->bFound;
  94. }
  95. //
  96. // get the pointer to task database block from hTask
  97. //
  98. PTDB
  99. GetTDB(
  100. WORD wTDB
  101. )
  102. {
  103. PTDB pTDB;
  104. pTDB = (PTDB)SEGPTR(wTDB, 0);
  105. if (NULL == pTDB || TDB_SIGNATURE != pTDB->TDB_sig) {
  106. LOGN(
  107. eDbgLevelError,
  108. "[GetTDB] TDB is invalid for task 0x%x",
  109. (DWORD)wTDB);
  110. return NULL;
  111. }
  112. return pTDB;
  113. }
  114. //
  115. // GetModName
  116. // wTDB - TDB entry
  117. // szModName - pointer to the buffer that receives module name
  118. // buffer should be at least 9 characters long
  119. //
  120. // returns FALSE if the entry is invalid
  121. BOOL
  122. GetModName(
  123. WORD wTDB,
  124. PCH szModName
  125. )
  126. {
  127. PTDB pTDB;
  128. PCH pch;
  129. pTDB = GetTDB(wTDB);
  130. if (NULL == pTDB) {
  131. return FALSE;
  132. }
  133. RtlCopyMemory(szModName, pTDB->TDB_ModName, 8 * sizeof(CHAR)); // we have modname now
  134. szModName[8] = '\0';
  135. pch = &szModName[8];
  136. while (*(--pch) == ' ') {
  137. *pch = 0;
  138. }
  139. return TRUE;
  140. }
  141. //
  142. // ShimGetTaskFileName
  143. // IN wTask - 16-bit task handle
  144. // Returns:
  145. // Fully qualified exe that is running in this task's context
  146. //
  147. PSZ
  148. ShimGetTaskFileName(
  149. WORD wTask
  150. )
  151. {
  152. PSZ pszFileName = NULL;
  153. PTDB pTDB;
  154. pTDB = GetTDB(wTask);
  155. if (NULL == pTDB) {
  156. // this is really bad -- the module is invalid, debug output is generated by GetTDB
  157. return pszFileName;
  158. }
  159. if (NULL == pTDB->TDB_pModule) {
  160. LOGN(
  161. eDbgLevelError,
  162. "[ShimGetTaskFileName] module pointer is NULL for 0x%x",
  163. (DWORD)wTask);
  164. return pszFileName;
  165. }
  166. pszFileName = (PSZ)SEGPTR(pTDB->TDB_pModule, (*(WORD *)SEGPTR(pTDB->TDB_pModule, 10)) + 8);
  167. return pszFileName;
  168. }
  169. PSZ
  170. ShimGetTaskEnvptr(
  171. WORD hTask16
  172. )
  173. {
  174. PTDB pTDB = GetTDB(hTask16);
  175. PSZ pszEnv = NULL;
  176. PDOSPDB pPSP;
  177. if (NULL == pTDB) {
  178. LOGN( eDbgLevelError,
  179. "[ShimGetTaskEnvptr] Bad TDB entry 0x%x", hTask16);
  180. return NULL;
  181. }
  182. //
  183. // Prepare environment data - this buffer is used when we're starting a new task from the
  184. // root of the chain (as opposed to spawning from an existing 16-bit task)
  185. //
  186. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  187. if (pPSP != NULL) {
  188. pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0);
  189. }
  190. return pszEnv;
  191. }
  192. // IsWowExec
  193. // IN wTDB - entry into the task database
  194. // Returns:
  195. // TRUE if this particular entry points to WOWEXEC
  196. //
  197. // Note:
  198. // WOWEXEC is a special stub module that always runs on NTVDM
  199. // new tasks are spawned by wowexec (in the most typical case)
  200. // it is therefore the "root" module and it's environment's contents
  201. // should not be counted, since we don't know what was ntvdm's parent process
  202. //
  203. BOOL
  204. IsWOWExec(
  205. WORD wTDB
  206. )
  207. {
  208. PTDB pTDB;
  209. PTDB pTDBParent;
  210. CHAR szModName[9];
  211. pTDB = GetTDB(wTDB);
  212. if (NULL == pTDB) {
  213. LOGN(
  214. eDbgLevelError,
  215. "[IsWOWExec] Bad TDB entry 0x%x",
  216. (DWORD)wTDB);
  217. return FALSE;
  218. }
  219. if (!GetModName(wTDB, szModName)) { // can we get modname ?
  220. LOGN(
  221. eDbgLevelError,
  222. "[IsWOWExec] GetModName failed.");
  223. return FALSE;
  224. }
  225. return (0 == _strcmpi(szModName, "wowexec")); // is the module named WOWEXEC ?
  226. }
  227. //
  228. // ImportWowApis
  229. // Function imports necessary apis from wow32.dll and vdmdbg.dll
  230. //
  231. //
  232. BOOL
  233. ImportWowApis(
  234. VOID
  235. )
  236. {
  237. g_hWow32 = LoadLibraryW(g_wszWOW32ModName);
  238. if (g_hWow32 == NULL) {
  239. LOGN(
  240. eDbgLevelError,
  241. "[ImportWowApis] Failed to load wow32.dll Error 0x%x",
  242. GetLastError());
  243. goto Fail;
  244. }
  245. g_pfnWOWGetVDMPointer = (PFNWOWGetVDMPointer)GetProcAddress(g_hWow32, "WOWGetVDMPointer");
  246. if (g_pfnWOWGetVDMPointer == NULL) {
  247. LOGN(
  248. eDbgLevelError,
  249. "[ImportWowApis] Failed to get address of WOWGetVDMPointer Error 0x%x",
  250. GetLastError());
  251. goto Fail;
  252. }
  253. g_hVdmDbg = LoadLibraryW(g_wszVdmDbgModName);
  254. if (g_hVdmDbg == NULL) {
  255. LOGN(
  256. eDbgLevelError,
  257. "[ImportWowApis] Failed to load vdmdbg.dll Error 0x%x",
  258. GetLastError());
  259. goto Fail;
  260. }
  261. g_pfnVDMEnumTaskWOW = (PFNVDMEnumTaskWOW)GetProcAddress(g_hVdmDbg, "VDMEnumTaskWOW");
  262. if (g_pfnVDMEnumTaskWOW == NULL) {
  263. LOGN(
  264. eDbgLevelError,
  265. "[ImportWowApis] Failed to get address of VDMEnumTaskWOW Error 0x%x",
  266. GetLastError());
  267. goto Fail;
  268. }
  269. g_bInitialized = TRUE;
  270. return TRUE;
  271. Fail:
  272. if (g_hWow32) {
  273. FreeLibrary(g_hWow32);
  274. g_hWow32 = NULL;
  275. }
  276. if (g_hVdmDbg) {
  277. FreeLibrary(g_hVdmDbg);
  278. g_hVdmDbg = NULL;
  279. }
  280. g_pfnWOWGetVDMPointer = NULL;
  281. g_pfnVDMEnumTaskWOW = NULL;
  282. return FALSE;
  283. }
  284. /////////////////////////////////////////////////////////////////////////////////////////////
  285. //
  286. //
  287. // WOWTaskList
  288. //
  289. // We maintain a shadow list of running wow tasks complete with respective process history and
  290. // inherited process history
  291. //
  292. //
  293. typedef struct tagWOWTASKLISTITEM* PWOWTASKLISTITEM;
  294. typedef struct tagWOWTASKLISTITEM {
  295. WORD hTask16; // 16-bit tdb entry
  296. DWORD dwThreadId; // thread id of the task
  297. WOWENVDATA EnvData; // environment data (process history, compat layer, etc)
  298. PWOWTASKLISTITEM pTaskNext;
  299. } WOWTASKLISTITEM;
  300. PWOWTASKLISTITEM g_pWowTaskList;
  301. /*++
  302. FindWowTaskInfo
  303. IN hTask16 16-bit task's handle
  304. IN dwThreadId OPTIONAL 32-bit thread id of the task, might be 0
  305. Returns: pointer to the task information structure
  306. --*/
  307. PWOWTASKLISTITEM
  308. FindWowTaskInfo(
  309. WORD hTask16,
  310. DWORD dwThreadId
  311. )
  312. {
  313. PWOWTASKLISTITEM pTask = g_pWowTaskList;
  314. while (NULL != pTask) {
  315. if (hTask16 == pTask->hTask16) {
  316. if (dwThreadId == 0 || dwThreadId == pTask->dwThreadId) {
  317. break;
  318. }
  319. }
  320. pTask = pTask->pTaskNext;
  321. }
  322. return pTask;
  323. }
  324. /*++
  325. UpdateWowTaskList
  326. IN hTask16 16-bit task's handle
  327. Returns: True if the task was added successfully
  328. Note: wowexec is not among the "legitimate" tasks
  329. --*/
  330. BOOL
  331. UpdateWowTaskList(
  332. WORD hTask16
  333. )
  334. {
  335. PTDB pTDB;
  336. WORD wTaskParent;
  337. PWOWTASKLISTITEM pTaskParent = NULL;
  338. LPSTR lpszFileName;
  339. PSZ pszEnv;
  340. WOWENVDATA EnvData;
  341. PWOWENVDATA pData = NULL;
  342. DWORD dwLength;
  343. PWOWTASKLISTITEM pTaskNew;
  344. PCH pBuffer;
  345. PDOSPDB pPSP;
  346. BOOL bSuccess;
  347. //
  348. // see that we are initialized, import apis
  349. //
  350. if (!g_bInitialized) { // first call, link apis
  351. bSuccess = ImportWowApis();
  352. if (!bSuccess) {
  353. LOGN(
  354. eDbgLevelError,
  355. "[UpdateWowTaskList] Failed to import apis.");
  356. return FALSE;
  357. }
  358. }
  359. //
  360. // If this task is WOWEXEC -- just return, it's not an error condition, but we don't need
  361. // wowexec in our list
  362. //
  363. if (IsWOWExec(hTask16)) { // this is ok, we don't want wowexec
  364. return FALSE;
  365. }
  366. //
  367. // next, see what the parent item is, to do so -- access it through TDB
  368. //
  369. pTDB = GetTDB(hTask16);
  370. if (NULL == pTDB) {
  371. LOGN(
  372. eDbgLevelError,
  373. "[UpdateWowTaskList] Bad TDB entry 0x%x",
  374. hTask16);
  375. return FALSE;
  376. }
  377. //
  378. // Prepare environment data - this buffer is used when we're starting a new task from the
  379. // root of the chain (as opposed to spawning from an existing 16-bit task)
  380. //
  381. RtlZeroMemory(&EnvData, sizeof(EnvData));
  382. pData = &EnvData;
  383. wTaskParent = pTDB->TDB_Parent;
  384. if (IsWOWExec(wTaskParent) || GetTDB(wTaskParent) == NULL) {
  385. //
  386. // Root task, extract process history, compat layer, etc
  387. //
  388. pszEnv = NULL;
  389. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  390. if (pPSP != NULL) {
  391. pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0);
  392. }
  393. //
  394. // we have a pointer to the current environment here, pData is initialized
  395. //
  396. if (pszEnv != NULL) {
  397. pData->pszProcessHistory = ShimFindEnvironmentVar(g_szProcessHistoryVar,
  398. pszEnv,
  399. &pData->pszProcessHistoryVal);
  400. pData->pszCompatLayer = ShimFindEnvironmentVar(g_szCompatLayerVar,
  401. pszEnv,
  402. &pData->pszCompatLayerVal);
  403. pData->pszShimFileLog = ShimFindEnvironmentVar(g_szShimFileLogVar,
  404. pszEnv,
  405. &pData->pszShimFileLogVal);
  406. }
  407. } else {
  408. //
  409. // Not a root task, find parent process
  410. //
  411. pTaskParent = FindWowTaskInfo(wTaskParent, 0); // we can't determine which thread owns the task
  412. if (pTaskParent == NULL) {
  413. //
  414. // something is very wrong
  415. // we can't inherit
  416. //
  417. LOGN(
  418. eDbgLevelError,
  419. "[UpdateWowTaskList] Task 0x%x is not root but parent not listed 0x%x",
  420. (DWORD)hTask16,
  421. (DWORD)wTaskParent);
  422. //
  423. // we still allow building up process history. The initial variables will be empty
  424. //
  425. } else {
  426. //
  427. // inherit everything from the parent and add it's module name (later)
  428. //
  429. pData = &pTaskParent->EnvData;
  430. }
  431. }
  432. //
  433. // Get the filename involved
  434. //
  435. //
  436. lpszFileName = ShimGetTaskFileName(hTask16);
  437. //
  438. // now calculate how much space is required to hold all of the data
  439. //
  440. dwLength = sizeof(WOWTASKLISTITEM) +
  441. (NULL == pData->pszProcessHistory ? 0 : (strlen(pData->pszProcessHistory) + 1) * sizeof(CHAR)) +
  442. (NULL == pData->pszCompatLayer ? 0 : (strlen(pData->pszCompatLayer) + 1) * sizeof(CHAR)) +
  443. (NULL == pData->pszShimFileLog ? 0 : (strlen(pData->pszShimFileLog) + 1) * sizeof(CHAR)) +
  444. (NULL == pData->pszCurrentProcessHistory ? 0 : (strlen(pData->pszCurrentProcessHistory) + 1) * sizeof(CHAR)) +
  445. (NULL == lpszFileName ? 0 : (strlen(lpszFileName) + 1) * sizeof(CHAR));
  446. pTaskNew = (PWOWTASKLISTITEM)ShimMalloc(dwLength);
  447. if (pTaskNew == NULL) {
  448. LOGN(
  449. eDbgLevelError,
  450. "[UpdateWowTaskList] failed to allocate 0x%x bytes",
  451. dwLength);
  452. return FALSE;
  453. }
  454. RtlZeroMemory(pTaskNew, dwLength);
  455. //
  456. // now this entry has to be setup
  457. // process history is first
  458. //
  459. pBuffer = (PCH)(pTaskNew + 1);
  460. pTaskNew->hTask16 = hTask16;
  461. pTaskNew->dwThreadId = GetCurrentThreadId();
  462. if (pData->pszProcessHistory != NULL) {
  463. //
  464. // Copy process history. The processHistoryVal is a pointer into the buffer
  465. // pointed to by pszProcessHistory: __PROCESS_HISTORY=c:\foo;c:\docs~1\install
  466. // then pszProcessHistoryVal will point here ---------^
  467. //
  468. // we are copying the data and moving the pointer using the calculated offset
  469. pTaskNew->EnvData.pszProcessHistory = pBuffer;
  470. strcpy(pTaskNew->EnvData.pszProcessHistory, pData->pszProcessHistory);
  471. pTaskNew->EnvData.pszProcessHistoryVal = pTaskNew->EnvData.pszProcessHistory +
  472. (INT)(pData->pszProcessHistoryVal - pData->pszProcessHistory);
  473. //
  474. // There is enough space in the buffer to accomodate all the strings, so
  475. // move pointer past current string to point at the "empty" space
  476. //
  477. pBuffer += strlen(pData->pszProcessHistory) + 1;
  478. }
  479. if (pData->pszCompatLayer != NULL) {
  480. pTaskNew->EnvData.pszCompatLayer = pBuffer;
  481. strcpy(pTaskNew->EnvData.pszCompatLayer, pData->pszCompatLayer);
  482. pTaskNew->EnvData.pszCompatLayerVal = pTaskNew->EnvData.pszCompatLayer +
  483. (INT)(pData->pszCompatLayerVal - pData->pszCompatLayer);
  484. pBuffer += strlen(pData->pszCompatLayer) + 1;
  485. }
  486. if (pData->pszShimFileLog != NULL) {
  487. pTaskNew->EnvData.pszShimFileLog = pBuffer;
  488. strcpy(pTaskNew->EnvData.pszShimFileLog, pData->pszShimFileLog);
  489. pTaskNew->EnvData.pszShimFileLogVal = pTaskNew->EnvData.pszShimFileLog +
  490. (INT)(pData->pszShimFileLogVal - pData->pszShimFileLog);
  491. pBuffer += strlen(pData->pszShimFileLog) + 1;
  492. }
  493. if (pData->pszCurrentProcessHistory != NULL || lpszFileName != NULL) {
  494. //
  495. // Now process history
  496. //
  497. pTaskNew->EnvData.pszCurrentProcessHistory = pBuffer;
  498. if (pData->pszCurrentProcessHistory != NULL) {
  499. strcpy(pTaskNew->EnvData.pszCurrentProcessHistory, pData->pszCurrentProcessHistory);
  500. strcat(pTaskNew->EnvData.pszCurrentProcessHistory, ";");
  501. }
  502. if (lpszFileName != NULL) {
  503. strcat(pTaskNew->EnvData.pszCurrentProcessHistory, lpszFileName);
  504. }
  505. }
  506. LOGN(
  507. eDbgLevelInfo,
  508. "[UpdateWowTaskList] Running : \"%s\"",
  509. lpszFileName);
  510. LOGN(
  511. eDbgLevelInfo,
  512. "[UpdateWowTaskList] ProcessHistory : \"%s\"",
  513. pTaskNew->EnvData.pszCurrentProcessHistory);
  514. LOGN(
  515. eDbgLevelInfo,
  516. "[UpdateWowTaskList] BaseProcessHistory: \"%s\"",
  517. pTaskNew->EnvData.pszProcessHistory);
  518. LOGN(
  519. eDbgLevelInfo,
  520. "[UpdateWowTaskList] CompatLayer : \"%s\"",
  521. pTaskNew->EnvData.pszCompatLayer);
  522. //
  523. // We are done, link the entry into the list
  524. //
  525. pTaskNew->pTaskNext = g_pWowTaskList;
  526. g_pWowTaskList = pTaskNew;
  527. return TRUE;
  528. }
  529. /*++
  530. CleanupWowTaskList
  531. IN hTask16 16-bit task handle that is to be removed from the list of running tasks
  532. Returns : TRUE if the function succeeds
  533. --*/
  534. BOOL
  535. CleanupWowTaskList(
  536. WORD hTask16
  537. )
  538. {
  539. PWOWTASKLISTITEM pTask = g_pWowTaskList;
  540. PWOWTASKLISTITEM pTaskPrev = NULL;
  541. while (pTask != NULL) {
  542. if (pTask->hTask16 == hTask16) {
  543. // this is the item
  544. break;
  545. }
  546. pTaskPrev = pTask;
  547. pTask = pTask->pTaskNext;
  548. }
  549. if (pTask == NULL) {
  550. LOGN(
  551. eDbgLevelError,
  552. "[CleanupWowTaskList] Failed to locate task information for 0x%x",
  553. (DWORD)hTask16);
  554. return FALSE;
  555. }
  556. if (pTaskPrev == NULL) {
  557. g_pWowTaskList = pTask->pTaskNext;
  558. } else {
  559. pTaskPrev->pTaskNext = pTask->pTaskNext;
  560. }
  561. ShimFree(pTask);
  562. return TRUE;
  563. }
  564. /*++
  565. ShimRetrieveVariablesEx
  566. IN pData Structure that receives pointers to all the relevant environment information
  567. for the calling thread. The threads are scheduled non-preemptively by user and
  568. threadid is used to identify the calling 16-bit task
  569. All the real work on information retrieval is done in UpdateWowTaskList
  570. Returns: TRUE if success
  571. --*/
  572. BOOL
  573. ShimRetrieveVariablesEx(
  574. PWOWENVDATA pData
  575. )
  576. {
  577. DWORD dwProcessId = GetCurrentProcessId();
  578. DWORD dwThreadId = GetCurrentThreadId();
  579. PWOWTASKLISTITEM pTask;
  580. FINDWOWTASKDATA FindData;
  581. WORD hTask;
  582. BOOL bSuccess;
  583. RtlZeroMemory(pData, sizeof(*pData));
  584. if (!g_bInitialized) { // first call, link apis
  585. bSuccess = ImportWowApis();
  586. if (!bSuccess) {
  587. LOGN(
  588. eDbgLevelError,
  589. "[ShimRetrieveVariablesEx] Failed to import apis.");
  590. return FALSE;
  591. }
  592. }
  593. if (!FindWowTask(dwProcessId, dwThreadId, &FindData)) {
  594. LOGN(
  595. eDbgLevelError,
  596. "[ShimRetrieveVariablesEx] Task not found ProcessId 0x%x ThreadId 0x%x",
  597. dwProcessId,
  598. dwThreadId);
  599. return FALSE;
  600. }
  601. hTask = FindData.hTask16;
  602. pTask = FindWowTaskInfo(hTask, dwThreadId);
  603. if (pTask == NULL) {
  604. LOGN(
  605. eDbgLevelError,
  606. "[ShimRetrieveVariablesEx] Failed to locate wow task.");
  607. return FALSE;
  608. }
  609. //
  610. // Found this one. Copy the info.
  611. //
  612. RtlMoveMemory(pData, &pTask->EnvData, sizeof(*pData));
  613. return TRUE;
  614. }
  615. /*++
  616. ShimThisProcess
  617. Function invokes Shim Engine for dynamic shimming of the current process
  618. Which happens to be ntvdm, naturally. This ntvdm is a separate ntvdm
  619. (which is insured through various checks in CheckAndShimNTVDM)
  620. --*/
  621. BOOL
  622. ShimThisProcess(
  623. HMODULE hModShimEngine,
  624. HSDB hSDB,
  625. SDBQUERYRESULT* pQueryResult
  626. )
  627. {
  628. typedef BOOL (WINAPI *PFNDynamicShim)(LPCWSTR , HSDB , SDBQUERYRESULT*, LPCSTR);
  629. PFNDynamicShim pfnDynamicShim = NULL;
  630. WCHAR wszFileName[MAX_PATH];
  631. DWORD dwLength;
  632. pfnDynamicShim = (PFNDynamicShim) GetProcAddress(hModShimEngine, "SE_DynamicShim");
  633. if (NULL == pfnDynamicShim) {
  634. LOGN( eDbgLevelError,
  635. "[ShimThisProcess] failed to obtain dynamic shim proc address\n");
  636. return FALSE;
  637. }
  638. dwLength = GetModuleFileNameW(GetModuleHandle(NULL), wszFileName, CHARCOUNT(wszFileName));
  639. if (!dwLength || dwLength > CHARCOUNT(wszFileName)) {
  640. LOGN( eDbgLevelError,
  641. "[ShimThisProcess] failed to obtain module file name\n");
  642. return FALSE;
  643. }
  644. return pfnDynamicShim(wszFileName, hSDB, pQueryResult, NULL);
  645. }
  646. /*++
  647. CheckAndShimNTVDM
  648. Procedure checks ntvdm application for having to be shimmed. If an application is located in
  649. appcompat database, this ntvdm would have to be running as a separate ntvdm (explorer is shimmed as
  650. well, as a result it will have checked the binary first and set the separate vdm flag in CreateProcess)
  651. Further, this call comes through InitTask (intercepted between ntvdm and user32) -- as a parameter it
  652. takes hTask16 - which we're able to use to retrieve application's environment and other important
  653. information.
  654. --*/
  655. BOOL
  656. CheckAndShimNTVDM(
  657. WORD hTask16
  658. )
  659. {
  660. HMODULE hModShimEngine;
  661. PSZ pszTaskFileName = NULL;
  662. CString csTaskFileName;
  663. DWORD dwExeCount;
  664. PSZ pszEnv = NULL;
  665. PTDB pTDB = NULL;
  666. PVOID pEnvNew = NULL;
  667. PDOSPDB pPSP;
  668. BOOL bSuccess = FALSE;
  669. BOOL bMatch;
  670. BOOL bNewEnv = FALSE;
  671. HSDB hSDB;
  672. NTSTATUS Status;
  673. SDBQUERYRESULT QueryResult;
  674. DWORD dwFlags;
  675. hModShimEngine = GetModuleHandle(TEXT("shim.dll"));
  676. if (hModShimEngine == NULL) {
  677. // impossible -- shim.dll is not injected!!!
  678. return FALSE;
  679. }
  680. if (g_pSeparateWow != NULL && *g_pSeparateWow == FALSE) {
  681. //
  682. // not a separate wow
  683. //
  684. LOGN( eDbgLevelError,
  685. "[CheckAndShimNTVDM] running in shared wow, no shimming\n");
  686. return FALSE;
  687. }
  688. if (!g_bInitialized) { // first call, link apis
  689. bSuccess = ImportWowApis();
  690. if (!bSuccess) {
  691. LOGN( eDbgLevelError,
  692. "[CheckAndShimNTVDM] Failed to import apis.\n");
  693. return FALSE;
  694. }
  695. }
  696. if (IsWOWExec(hTask16)) {
  697. LOGN( eDbgLevelError,
  698. "[CheckAndShimNTVDM] not touching wowexec\n");
  699. return FALSE;
  700. }
  701. csTaskFileName = ShimGetTaskFileName(hTask16);
  702. if (csTaskFileName.IsEmpty()) {
  703. LOGN( eDbgLevelError,
  704. "[CheckAndShimNTVDM] failed to get the filename for task 0x%lx\n", hTask16);
  705. return FALSE;
  706. }
  707. //
  708. // init database
  709. //
  710. hSDB = SdbInitDatabase(0, NULL);
  711. if (hSDB == NULL) {
  712. LOGN( eDbgLevelError,
  713. "[CheckAndShimNTVDM] failed to init shim database\n");
  714. return FALSE;
  715. }
  716. //
  717. // process history please --
  718. // if we end up here, we are a separate ntvdm
  719. // running with a process history in the env, was retrieved in init
  720. //
  721. pTDB = GetTDB(hTask16);
  722. if (NULL == pTDB) {
  723. LOGN( eDbgLevelError, "[UpdateWowTaskList] Bad TDB entry 0x%x", hTask16);
  724. return FALSE;
  725. }
  726. //
  727. // Prepare environment data - this buffer is used when we're starting a new task from the
  728. // root of the chain (as opposed to spawning from an existing 16-bit task)
  729. //
  730. pszEnv = ShimGetTaskEnvptr(hTask16);
  731. if (NULL != pszEnv) {
  732. Status = ShimCloneEnvironment(&pEnvNew, (LPVOID)pszEnv, FALSE);
  733. if (!NT_SUCCESS(Status)) {
  734. LOGN( eDbgLevelError,
  735. "[CheckAndShimNTVDM] cannot clone environment 0x%lx\n", Status);
  736. pEnvNew = NULL;
  737. bNewEnv = TRUE;
  738. }
  739. //
  740. // if this call has come the way of VDM - we need to carry over our environment stuff
  741. // which is stored separately in this shim
  742. //
  743. // should the call to ShimCloneEnvironment fail, we will have pEnvNew == NULL
  744. // and bNewEnv = TRUE, as a result, we shall try again to clone the environment
  745. dwFlags = CREATE_UNICODE_ENVIRONMENT;
  746. pEnvNew = ShimCreateWowEnvironment_U(pEnvNew, &dwFlags, bNewEnv);
  747. }
  748. //
  749. // run detection please
  750. //
  751. bMatch = SdbGetMatchingExe(hSDB,
  752. (LPCWSTR)csTaskFileName,
  753. NULL, // we can give out module name as well -- but WHY?
  754. (LPCWSTR)pEnvNew,
  755. 0,
  756. &QueryResult);
  757. if (bMatch) {
  758. bSuccess = ShimThisProcess(hModShimEngine, hSDB, &QueryResult);
  759. }
  760. if (pEnvNew != NULL) {
  761. ShimFreeEnvironment(pEnvNew);
  762. }
  763. return bSuccess;
  764. }
  765. IMPLEMENT_SHIM_END