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.

1006 lines
26 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. IMPLEMENT_SHIM_BEGIN(Win2kPropagateLayer)
  16. #include "ShimHookMacro.h"
  17. #include "Win2kPropagateLayer.h"
  18. typedef struct tagFINDWOWTASKDATA {
  19. BOOL bFound;
  20. DWORD dwProcessId;
  21. DWORD dwThreadId;
  22. WORD hMod16;
  23. WORD hTask16;
  24. } FINDWOWTASKDATA, *PFINDWOWTASKDATA;
  25. //
  26. // Dynamically Linked apis
  27. //
  28. // from WOW32.dll
  29. //
  30. typedef LPVOID (WINAPI *PFNWOWGetVDMPointer)(DWORD vp,
  31. DWORD dwBytes,
  32. BOOL fProtectedMode);
  33. //
  34. // from vdmdbg.dll - defined in the header file
  35. //
  36. //
  37. typedef INT (WINAPI *PFNVDMEnumTaskWOW)(DWORD dwProcessId,
  38. TASKENUMPROC fp,
  39. LPARAM lparam);
  40. //
  41. // Api importing -- modules
  42. //
  43. WCHAR g_wszWOW32ModName[] = L"wow32.dll";
  44. WCHAR g_wszVdmDbgModName[] = L"VdmDbg.dll";
  45. //
  46. // Api importing - module handles and function pointers
  47. //
  48. HMODULE g_hWow32;
  49. HMODULE g_hVdmDbg;
  50. BOOL g_bInitialized; // set to true when imports are initialized
  51. PFNWOWGetVDMPointer g_pfnWOWGetVDMPointer;
  52. PFNVDMEnumTaskWOW g_pfnVDMEnumTaskWOW;
  53. extern BOOL* g_pSeparateWow;
  54. //
  55. // function in this module to import apis
  56. //
  57. BOOL ImportWowApis(VOID);
  58. //
  59. // Marcro to access 16-bit memory
  60. //
  61. #define SEGPTR(seg,off) ((g_pfnWOWGetVDMPointer)((((ULONG)seg) << 16) | (off), 0, TRUE))
  62. //
  63. // task enum proc, called back from vdmdbg
  64. //
  65. BOOL WINAPI MyTaskEnumProc(
  66. DWORD dwThreadId,
  67. WORD hMod16,
  68. WORD hTask16,
  69. LPARAM lParam
  70. )
  71. {
  72. PFINDWOWTASKDATA pFindData = (PFINDWOWTASKDATA)lParam;
  73. if (dwThreadId == pFindData->dwThreadId) {
  74. pFindData->hMod16 = hMod16;
  75. pFindData->hTask16 = hTask16;
  76. pFindData->bFound = TRUE;
  77. return TRUE;
  78. }
  79. return FALSE;
  80. }
  81. BOOL FindWowTask(
  82. DWORD dwProcessId,
  83. DWORD dwThreadId,
  84. PFINDWOWTASKDATA pFindData
  85. )
  86. {
  87. RtlZeroMemory(pFindData, sizeof(*pFindData));
  88. pFindData->dwProcessId = dwProcessId;
  89. pFindData->dwThreadId = dwThreadId;
  90. g_pfnVDMEnumTaskWOW(dwProcessId, (TASKENUMPROC)MyTaskEnumProc, (LPARAM)pFindData);
  91. return pFindData->bFound;
  92. }
  93. //
  94. // get the pointer to task database block from hTask
  95. //
  96. PTDB
  97. GetTDB(
  98. WORD wTDB
  99. )
  100. {
  101. PTDB pTDB;
  102. pTDB = (PTDB)SEGPTR(wTDB, 0);
  103. if (NULL == pTDB || TDB_SIGNATURE != pTDB->TDB_sig) {
  104. LOGN(
  105. eDbgLevelError,
  106. "[GetTDB] TDB is invalid for task 0x%x",
  107. (DWORD)wTDB);
  108. return NULL;
  109. }
  110. return pTDB;
  111. }
  112. //
  113. // GetModName
  114. // wTDB - TDB entry
  115. // szModName - pointer to the buffer that receives module name
  116. // buffer should be at least 9 characters long
  117. //
  118. // returns FALSE if the entry is invalid
  119. BOOL
  120. GetModName(
  121. WORD wTDB,
  122. PCH szModName
  123. )
  124. {
  125. PTDB pTDB;
  126. PCH pch;
  127. pTDB = GetTDB(wTDB);
  128. if (NULL == pTDB) {
  129. return FALSE;
  130. }
  131. RtlCopyMemory(szModName, pTDB->TDB_ModName, 8 * sizeof(CHAR)); // we have modname now
  132. szModName[8] = '\0';
  133. pch = &szModName[8];
  134. while (--pch >= szModName && *pch == ' ') {
  135. *pch = 0;
  136. }
  137. if( pch < szModName ) {
  138. return FALSE;
  139. }
  140. return TRUE;
  141. }
  142. //
  143. // ShimGetTaskFileName
  144. // IN wTask - 16-bit task handle
  145. // Returns:
  146. // Fully qualified exe that is running in this task's context
  147. //
  148. PSZ
  149. ShimGetTaskFileName(
  150. WORD wTask
  151. )
  152. {
  153. PSZ pszFileName = NULL;
  154. PTDB pTDB;
  155. pTDB = GetTDB(wTask);
  156. if (NULL == pTDB) {
  157. // this is really bad -- the module is invalid, debug output is generated by GetTDB
  158. return pszFileName;
  159. }
  160. if (NULL == pTDB->TDB_pModule) {
  161. LOGN(
  162. eDbgLevelError,
  163. "[ShimGetTaskFileName] module pointer is NULL for 0x%x",
  164. (DWORD)wTask);
  165. return pszFileName;
  166. }
  167. pszFileName = (PSZ)SEGPTR(pTDB->TDB_pModule, (*(WORD *)SEGPTR(pTDB->TDB_pModule, 10)) + 8);
  168. return pszFileName;
  169. }
  170. PSZ
  171. ShimGetTaskEnvptr(
  172. WORD hTask16
  173. )
  174. {
  175. PTDB pTDB = GetTDB(hTask16);
  176. PSZ pszEnv = NULL;
  177. PDOSPDB pPSP;
  178. if (NULL == pTDB) {
  179. LOGN( eDbgLevelError,
  180. "[ShimGetTaskEnvptr] Bad TDB entry 0x%x", hTask16);
  181. return NULL;
  182. }
  183. //
  184. // Prepare environment data - this buffer is used when we're starting a new task from the
  185. // root of the chain (as opposed to spawning from an existing 16-bit task)
  186. //
  187. pPSP = (PDOSPDB)SEGPTR(pTDB->TDB_PDB, 0); // psp
  188. if (pPSP != NULL) {
  189. pszEnv = (PCH)SEGPTR(pPSP->PDB_environ, 0);
  190. }
  191. return pszEnv;
  192. }
  193. // IsWowExec
  194. // IN wTDB - entry into the task database
  195. // Returns:
  196. // TRUE if this particular entry points to WOWEXEC
  197. //
  198. // Note:
  199. // WOWEXEC is a special stub module that always runs on NTVDM
  200. // new tasks are spawned by wowexec (in the most typical case)
  201. // it is therefore the "root" module and it's environment's contents
  202. // should not be counted, since we don't know what was ntvdm's parent process
  203. //
  204. BOOL
  205. IsWOWExec(
  206. WORD wTDB
  207. )
  208. {
  209. PTDB pTDB;
  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) + 2) * 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. // Keep track of how much of the buffer is left.
  461. size_t cchRemaining = dwLength - sizeof(WOWTASKLISTITEM);
  462. pTaskNew->hTask16 = hTask16;
  463. pTaskNew->dwThreadId = GetCurrentThreadId();
  464. if (pData->pszProcessHistory != NULL) {
  465. //
  466. // Copy process history. The processHistoryVal is a pointer into the buffer
  467. // pointed to by pszProcessHistory: __PROCESS_HISTORY=c:\foo;c:\docs~1\install
  468. // then pszProcessHistoryVal will point here ---------^
  469. //
  470. // we are copying the data and moving the pointer using the calculated offset
  471. pTaskNew->EnvData.pszProcessHistory = pBuffer;
  472. StringCchCopyExA(pTaskNew->EnvData.pszProcessHistory, cchRemaining, pData->pszProcessHistory, NULL, &cchRemaining, 0);
  473. pTaskNew->EnvData.pszProcessHistoryVal = pTaskNew->EnvData.pszProcessHistory +
  474. (INT)(pData->pszProcessHistoryVal - pData->pszProcessHistory);
  475. //
  476. // There is enough space in the buffer to accomodate all the strings, so
  477. // move pointer past current string to point at the "empty" space
  478. //
  479. pBuffer += strlen(pData->pszProcessHistory) + 1;
  480. }
  481. if (pData->pszCompatLayer != NULL) {
  482. pTaskNew->EnvData.pszCompatLayer = pBuffer;
  483. StringCchCopyExA(pTaskNew->EnvData.pszCompatLayer, cchRemaining, pData->pszCompatLayer, NULL, &cchRemaining, 0);
  484. pTaskNew->EnvData.pszCompatLayerVal = pTaskNew->EnvData.pszCompatLayer +
  485. (INT)(pData->pszCompatLayerVal - pData->pszCompatLayer);
  486. pBuffer += strlen(pData->pszCompatLayer) + 1;
  487. }
  488. if (pData->pszShimFileLog != NULL) {
  489. pTaskNew->EnvData.pszShimFileLog = pBuffer;
  490. StringCchCopyExA(pTaskNew->EnvData.pszShimFileLog, cchRemaining, pData->pszShimFileLog, NULL, &cchRemaining, 0);
  491. pTaskNew->EnvData.pszShimFileLogVal = pTaskNew->EnvData.pszShimFileLog +
  492. (INT)(pData->pszShimFileLogVal - pData->pszShimFileLog);
  493. pBuffer += strlen(pData->pszShimFileLog) + 1;
  494. }
  495. if (pData->pszCurrentProcessHistory != NULL || lpszFileName != NULL) {
  496. //
  497. // Now process history
  498. //
  499. pTaskNew->EnvData.pszCurrentProcessHistory = pBuffer;
  500. if (pData->pszCurrentProcessHistory != NULL) {
  501. StringCchCopyExA(pTaskNew->EnvData.pszCurrentProcessHistory, cchRemaining, pData->pszCurrentProcessHistory, NULL, &cchRemaining, 0);
  502. if (lpszFileName != NULL ) {
  503. StringCchCatExA(pTaskNew->EnvData.pszCurrentProcessHistory, cchRemaining, ";", NULL, &cchRemaining, 0);
  504. }
  505. }
  506. if (lpszFileName != NULL) {
  507. StringCchCatA(pTaskNew->EnvData.pszCurrentProcessHistory, cchRemaining, lpszFileName);
  508. }
  509. }
  510. LOGN(
  511. eDbgLevelInfo,
  512. "[UpdateWowTaskList] Running : \"%s\"",
  513. lpszFileName);
  514. LOGN(
  515. eDbgLevelInfo,
  516. "[UpdateWowTaskList] ProcessHistory : \"%s\"",
  517. pTaskNew->EnvData.pszCurrentProcessHistory);
  518. LOGN(
  519. eDbgLevelInfo,
  520. "[UpdateWowTaskList] BaseProcessHistory: \"%s\"",
  521. pTaskNew->EnvData.pszProcessHistory);
  522. LOGN(
  523. eDbgLevelInfo,
  524. "[UpdateWowTaskList] CompatLayer : \"%s\"",
  525. pTaskNew->EnvData.pszCompatLayer);
  526. //
  527. // We are done, link the entry into the list
  528. //
  529. pTaskNew->pTaskNext = g_pWowTaskList;
  530. g_pWowTaskList = pTaskNew;
  531. return TRUE;
  532. }
  533. /*++
  534. CleanupWowTaskList
  535. IN hTask16 16-bit task handle that is to be removed from the list of running tasks
  536. Returns : TRUE if the function succeeds
  537. --*/
  538. BOOL
  539. CleanupWowTaskList(
  540. WORD hTask16
  541. )
  542. {
  543. PWOWTASKLISTITEM pTask = g_pWowTaskList;
  544. PWOWTASKLISTITEM pTaskPrev = NULL;
  545. while (pTask != NULL) {
  546. if (pTask->hTask16 == hTask16) {
  547. // this is the item
  548. break;
  549. }
  550. pTaskPrev = pTask;
  551. pTask = pTask->pTaskNext;
  552. }
  553. if (pTask == NULL) {
  554. LOGN(
  555. eDbgLevelError,
  556. "[CleanupWowTaskList] Failed to locate task information for 0x%x",
  557. (DWORD)hTask16);
  558. return FALSE;
  559. }
  560. if (pTaskPrev == NULL) {
  561. g_pWowTaskList = pTask->pTaskNext;
  562. } else {
  563. pTaskPrev->pTaskNext = pTask->pTaskNext;
  564. }
  565. ShimFree(pTask);
  566. return TRUE;
  567. }
  568. /*++
  569. ShimRetrieveVariablesEx
  570. IN pData Structure that receives pointers to all the relevant environment information
  571. for the calling thread. The threads are scheduled non-preemptively by user and
  572. threadid is used to identify the calling 16-bit task
  573. All the real work on information retrieval is done in UpdateWowTaskList
  574. Returns: TRUE if success
  575. --*/
  576. BOOL
  577. ShimRetrieveVariablesEx(
  578. PWOWENVDATA pData
  579. )
  580. {
  581. DWORD dwProcessId = GetCurrentProcessId();
  582. DWORD dwThreadId = GetCurrentThreadId();
  583. PWOWTASKLISTITEM pTask;
  584. FINDWOWTASKDATA FindData;
  585. WORD hTask;
  586. BOOL bSuccess;
  587. RtlZeroMemory(pData, sizeof(*pData));
  588. if (!g_bInitialized) { // first call, link apis
  589. bSuccess = ImportWowApis();
  590. if (!bSuccess) {
  591. LOGN(
  592. eDbgLevelError,
  593. "[ShimRetrieveVariablesEx] Failed to import apis.");
  594. return FALSE;
  595. }
  596. }
  597. if (!FindWowTask(dwProcessId, dwThreadId, &FindData)) {
  598. LOGN(
  599. eDbgLevelError,
  600. "[ShimRetrieveVariablesEx] Task not found ProcessId 0x%x ThreadId 0x%x",
  601. dwProcessId,
  602. dwThreadId);
  603. return FALSE;
  604. }
  605. hTask = FindData.hTask16;
  606. pTask = FindWowTaskInfo(hTask, dwThreadId);
  607. if (pTask == NULL) {
  608. LOGN(
  609. eDbgLevelError,
  610. "[ShimRetrieveVariablesEx] Failed to locate wow task.");
  611. return FALSE;
  612. }
  613. //
  614. // Found this one. Copy the info.
  615. //
  616. RtlMoveMemory(pData, &pTask->EnvData, sizeof(*pData));
  617. return TRUE;
  618. }
  619. /*++
  620. ShimThisProcess
  621. Function invokes Shim Engine for dynamic shimming of the current process
  622. Which happens to be ntvdm, naturally. This ntvdm is a separate ntvdm
  623. (which is insured through various checks in CheckAndShimNTVDM)
  624. --*/
  625. BOOL
  626. ShimThisProcess(
  627. HMODULE hModShimEngine,
  628. HSDB hSDB,
  629. SDBQUERYRESULT* pQueryResult
  630. )
  631. {
  632. typedef BOOL (WINAPI *PFNDynamicShim)(LPCWSTR , HSDB , SDBQUERYRESULT*, LPCSTR, LPDWORD);
  633. PFNDynamicShim pfnDynamicShim = NULL;
  634. WCHAR wszFileName[MAX_PATH];
  635. DWORD dwLength;
  636. DWORD dwDynamicToken = 0;
  637. pfnDynamicShim = (PFNDynamicShim) GetProcAddress(hModShimEngine, "SE_DynamicShim");
  638. if (NULL == pfnDynamicShim) {
  639. LOGN( eDbgLevelError,
  640. "[ShimThisProcess] failed to obtain dynamic shim proc address\n");
  641. return FALSE;
  642. }
  643. dwLength = GetModuleFileNameW(GetModuleHandle(NULL), wszFileName, CHARCOUNT(wszFileName));
  644. if (!dwLength || dwLength == CHARCOUNT(wszFileName)) {
  645. LOGN( eDbgLevelError,
  646. "[ShimThisProcess] failed to obtain module file name\n");
  647. return FALSE;
  648. }
  649. return pfnDynamicShim(wszFileName, hSDB, pQueryResult, NULL, &dwDynamicToken);
  650. }
  651. /*++
  652. CheckAndShimNTVDM
  653. Procedure checks ntvdm application for having to be shimmed. If an application is located in
  654. appcompat database, this ntvdm would have to be running as a separate ntvdm (explorer is shimmed as
  655. well, as a result it will have checked the binary first and set the separate vdm flag in CreateProcess)
  656. Further, this call comes through InitTask (intercepted between ntvdm and user32) -- as a parameter it
  657. takes hTask16 - which we're able to use to retrieve application's environment and other important
  658. information.
  659. --*/
  660. BOOL
  661. CheckAndShimNTVDM(
  662. WORD hTask16
  663. )
  664. {
  665. HMODULE hModShimEngine;
  666. CString csTaskFileName;
  667. PSZ pszEnv = NULL;
  668. PTDB pTDB = NULL;
  669. PVOID pEnvNew = NULL;
  670. BOOL bSuccess = FALSE;
  671. BOOL bMatch;
  672. BOOL bNewEnv = FALSE;
  673. HSDB hSDB;
  674. NTSTATUS Status;
  675. SDBQUERYRESULT QueryResult;
  676. DWORD dwFlags;
  677. hModShimEngine = GetModuleHandle(TEXT("shim.dll"));
  678. if (hModShimEngine == NULL) {
  679. // impossible -- shim.dll is not injected!!!
  680. return FALSE;
  681. }
  682. if (g_pSeparateWow != NULL && *g_pSeparateWow == FALSE) {
  683. //
  684. // not a separate wow
  685. //
  686. LOGN( eDbgLevelError,
  687. "[CheckAndShimNTVDM] running in shared wow, no shimming\n");
  688. return FALSE;
  689. }
  690. if (!g_bInitialized) { // first call, link apis
  691. bSuccess = ImportWowApis();
  692. if (!bSuccess) {
  693. LOGN( eDbgLevelError,
  694. "[CheckAndShimNTVDM] Failed to import apis.\n");
  695. return FALSE;
  696. }
  697. }
  698. if (IsWOWExec(hTask16)) {
  699. LOGN( eDbgLevelError,
  700. "[CheckAndShimNTVDM] not touching wowexec\n");
  701. return FALSE;
  702. }
  703. csTaskFileName = ShimGetTaskFileName(hTask16);
  704. if (csTaskFileName.IsEmpty()) {
  705. LOGN( eDbgLevelError,
  706. "[CheckAndShimNTVDM] failed to get the filename for task 0x%lx\n", hTask16);
  707. return FALSE;
  708. }
  709. //
  710. // init database
  711. //
  712. hSDB = SdbInitDatabase(0, NULL);
  713. if (hSDB == NULL) {
  714. LOGN( eDbgLevelError,
  715. "[CheckAndShimNTVDM] failed to init shim database\n");
  716. return FALSE;
  717. }
  718. //
  719. // process history please --
  720. // if we end up here, we are a separate ntvdm
  721. // running with a process history in the env, was retrieved in init
  722. //
  723. pTDB = GetTDB(hTask16);
  724. if (NULL == pTDB) {
  725. LOGN( eDbgLevelError, "[UpdateWowTaskList] Bad TDB entry 0x%x", hTask16);
  726. return FALSE;
  727. }
  728. //
  729. // Prepare environment data - this buffer is used when we're starting a new task from the
  730. // root of the chain (as opposed to spawning from an existing 16-bit task)
  731. //
  732. pszEnv = ShimGetTaskEnvptr(hTask16);
  733. if (NULL != pszEnv) {
  734. Status = ShimCloneEnvironment(&pEnvNew, (LPVOID)pszEnv, FALSE);
  735. if (!NT_SUCCESS(Status)) {
  736. LOGN( eDbgLevelError,
  737. "[CheckAndShimNTVDM] cannot clone environment 0x%lx\n", Status);
  738. pEnvNew = NULL;
  739. bNewEnv = TRUE;
  740. }
  741. //
  742. // if this call has come the way of VDM - we need to carry over our environment stuff
  743. // which is stored separately in this shim
  744. //
  745. // should the call to ShimCloneEnvironment fail, we will have pEnvNew == NULL
  746. // and bNewEnv = TRUE, as a result, we shall try again to clone the environment
  747. dwFlags = CREATE_UNICODE_ENVIRONMENT;
  748. pEnvNew = ShimCreateWowEnvironment_U(pEnvNew, &dwFlags, bNewEnv);
  749. }
  750. //
  751. // run detection please
  752. //
  753. bMatch = SdbGetMatchingExe(hSDB,
  754. (LPCWSTR)csTaskFileName,
  755. NULL, // we can give out module name as well -- but WHY?
  756. (LPCWSTR)pEnvNew,
  757. 0,
  758. &QueryResult);
  759. if (bMatch) {
  760. bSuccess = ShimThisProcess(hModShimEngine, hSDB, &QueryResult);
  761. }
  762. if (pEnvNew != NULL) {
  763. ShimFreeEnvironment(pEnvNew);
  764. }
  765. return bSuccess;
  766. }
  767. IMPLEMENT_SHIM_END