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.

987 lines
24 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. EmulateMissingEXE.cpp
  5. Abstract:
  6. Win9x had scandskw.exe and defrag.exe in %windir%, NT does not.
  7. Whistler has a hack in the shell32 for scandisk for app compatability
  8. purposes. Whistler can also invoke defrag via
  9. "%windir%\system32\mmc.exe %windir%\system32\dfrg.msc".
  10. This shim redirects CreateProcess and Winexec to execute these two
  11. substitutes, as well as FindFile to indicate their presence.
  12. Notes:
  13. This is a general purpose shim.
  14. History:
  15. 01/02/2001 prashkud Created
  16. 02/18/2001 prashkud Merged HandleStartKeyword SHIM with this.
  17. 02/21/2001 prashkud Replaced most strings with CString class.
  18. --*/
  19. #include "precomp.h"
  20. IMPLEMENT_SHIM_BEGIN(EmulateMissingEXE)
  21. #include "ShimHookMacro.h"
  22. APIHOOK_ENUM_BEGIN
  23. APIHOOK_ENUM_ENTRY(CreateProcessA)
  24. APIHOOK_ENUM_ENTRY(CreateProcessW)
  25. APIHOOK_ENUM_ENTRY(WinExec)
  26. APIHOOK_ENUM_ENTRY(FindFirstFileA)
  27. APIHOOK_ENUM_ENTRY(FindFirstFileW)
  28. APIHOOK_ENUM_ENTRY_COMSERVER(SHELL32)
  29. APIHOOK_ENUM_END
  30. IMPLEMENT_COMSERVER_HOOK(SHELL32)
  31. // Type for the functions that builds the New EXES
  32. typedef BOOL (*_pfn_STUBFUNC)(CString&, CString&, BOOL);
  33. // Main Data structure to hold the New strings
  34. struct REPLACEENTRY {
  35. WCHAR *OrigExeName; // original EXE to be replaced
  36. _pfn_STUBFUNC pfnFuncName; // function to call to correct the name
  37. };
  38. CRITICAL_SECTION g_CritSec;
  39. WCHAR g_szSysDir[MAX_PATH]; // system directory for stubs to use
  40. BOOL StubScandisk(CString&, CString&, BOOL);
  41. BOOL StubDefrag(CString&, CString&, BOOL);
  42. BOOL StubStart(CString&, CString&, BOOL);
  43. BOOL StubControl(CString&, CString&, BOOL);
  44. BOOL StubDxDiag(CString&, CString&, BOOL);
  45. BOOL StubWinhlp(CString&, CString&, BOOL);
  46. BOOL StubRundll(CString&, CString&, BOOL);
  47. BOOL StubPbrush(CString&, CString&, BOOL);
  48. // Add variations of these missing Exes like in HandleStartKeyword
  49. // Start has been put at the top of the list as there seem to be more apps
  50. // that need the SHIM for this EXE than others. In fact there was a
  51. // seperate SHIM HandleStartKeyword that was merged with this.
  52. REPLACEENTRY g_ReplList[] = {
  53. {L"start", StubStart },
  54. {L"start.exe", StubStart },
  55. {L"scandskw", StubScandisk },
  56. {L"scandskw.exe", StubScandisk },
  57. {L"defrag", StubDefrag },
  58. {L"defrag.exe", StubDefrag },
  59. {L"control", StubControl },
  60. {L"control.exe", StubControl },
  61. {L"dxdiag", StubDxDiag },
  62. {L"dxdiag.exe", StubDxDiag },
  63. {L"winhelp", StubWinhlp },
  64. {L"winhelp.exe", StubWinhlp },
  65. {L"rundll", StubRundll },
  66. {L"rundll.exe", StubRundll },
  67. {L"Pbrush", StubPbrush },
  68. {L"Pbrush.exe", StubPbrush },
  69. // Always the last one
  70. {L"", NULL }
  71. };
  72. // Added to merge HandleStartKeyword
  73. // Link list of shell link object this pointers.
  74. struct THISPOINTER
  75. {
  76. THISPOINTER *next;
  77. LPCVOID pThisPointer;
  78. };
  79. THISPOINTER *g_pThisPointerList;
  80. /*++
  81. Function Description:
  82. Add a this pointer to the linked list of pointers. Does not add if the
  83. pointer is NULL or a duplicate.
  84. Arguments:
  85. IN pThisPointer - the pointer to add.
  86. Return Value:
  87. None
  88. History:
  89. 12/14/2000 maonis Created
  90. --*/
  91. VOID
  92. AddThisPointer(
  93. IN LPCVOID pThisPointer
  94. )
  95. {
  96. EnterCriticalSection(&g_CritSec);
  97. if (pThisPointer)
  98. {
  99. THISPOINTER *pPointer = g_pThisPointerList;
  100. while (pPointer)
  101. {
  102. if (pPointer->pThisPointer == pThisPointer)
  103. {
  104. return;
  105. }
  106. pPointer = pPointer->next;
  107. }
  108. pPointer = (THISPOINTER *) malloc(sizeof THISPOINTER);
  109. if (pPointer)
  110. {
  111. pPointer->pThisPointer = pThisPointer;
  112. pPointer->next = g_pThisPointerList;
  113. g_pThisPointerList = pPointer;
  114. }
  115. }
  116. LeaveCriticalSection(&g_CritSec);
  117. }
  118. /*++
  119. Function Description:
  120. Remove a this pointer if it can be found in the linked list of pointers.
  121. Arguments:
  122. IN pThisPointer - the pointer to remove.
  123. Return Value:
  124. TRUE if the pointer is found.
  125. FALSE if the pointer is not found.
  126. History:
  127. 12/14/2000 maonis Created
  128. --*/
  129. BOOL
  130. RemoveThisPointer(
  131. IN LPCVOID pThisPointer
  132. )
  133. {
  134. THISPOINTER *pPointer = g_pThisPointerList;
  135. THISPOINTER *last = NULL;
  136. BOOL lRet = FALSE;
  137. EnterCriticalSection(&g_CritSec);
  138. while (pPointer)
  139. {
  140. if (pPointer->pThisPointer == pThisPointer)
  141. {
  142. if (last)
  143. {
  144. last->next = pPointer->next;
  145. }
  146. else
  147. {
  148. g_pThisPointerList = pPointer->next;
  149. }
  150. free(pPointer);
  151. lRet = TRUE;
  152. break;
  153. }
  154. last = pPointer;
  155. pPointer = pPointer->next;
  156. }
  157. LeaveCriticalSection(&g_CritSec);
  158. return lRet;
  159. }
  160. /*++
  161. We are here because the application name: scandskw.exe, matches the one in the
  162. static array. Fill the News for scandskw.exe as:
  163. rundll32.exe shell32.dll,AppCompat_RunDLL SCANDSKW
  164. --*/
  165. BOOL
  166. StubScandisk(
  167. CString& csNewApplicationName,
  168. CString& csNewCommandLine,
  169. BOOL bExists
  170. )
  171. {
  172. csNewApplicationName = g_szSysDir;
  173. csNewApplicationName += L"\\rundll32.exe";
  174. csNewCommandLine = L"shell32.dll,AppCompat_RunDLL SCANDSKW";
  175. return TRUE;
  176. }
  177. /*++
  178. We are here because the application name: defrag.exe, matches the one in the
  179. static array. Fill the News for .exe as:
  180. %windir%\\system32\\mmc.exe %windir%\\system32\\dfrg.msc
  181. --*/
  182. BOOL
  183. StubDefrag(
  184. CString& csNewApplicationName,
  185. CString& csNewCommandLine,
  186. BOOL bExists
  187. )
  188. {
  189. csNewApplicationName = g_szSysDir;
  190. csNewApplicationName += L"\\mmc.exe";
  191. csNewCommandLine = g_szSysDir;
  192. csNewCommandLine += L"\\dfrg.msc";
  193. return TRUE;
  194. }
  195. /*++
  196. We are here because the application name: start.exe, matches the one in the
  197. static array. Fill the News for .exe as:
  198. %windir%\\system32\\cmd.exe" "/c start"
  199. Many applications have a "start.exe" in their current working directories
  200. which needs to take precendence over any New we make.
  201. --*/
  202. BOOL
  203. StubStart(
  204. CString& csNewApplicationName,
  205. CString& csNewCommandLine,
  206. BOOL bExists
  207. )
  208. {
  209. //
  210. // First check the current working directory for start.exe
  211. //
  212. if (bExists) {
  213. return FALSE;
  214. }
  215. //
  216. // There is no start.exe in the current working directory
  217. //
  218. csNewApplicationName = g_szSysDir;
  219. csNewApplicationName += L"\\cmd.exe";
  220. csNewCommandLine = L"/d /c start \"\"";
  221. return TRUE;
  222. }
  223. /*++
  224. We are here because the application name: control.exe, matches the one in the
  225. static array. Fill the News for .exe as:
  226. %windir%\\system32\\control.exe
  227. --*/
  228. BOOL
  229. StubControl(
  230. CString& csNewApplicationName,
  231. CString& csNewCommandLine,
  232. BOOL bExists
  233. )
  234. {
  235. csNewApplicationName = g_szSysDir;
  236. csNewApplicationName += L"\\control.exe";
  237. csNewCommandLine = L"";
  238. return TRUE;
  239. }
  240. /*++
  241. We are here because the application name: dxdiag.exe, matches the one in the
  242. static array. Fill the News for .exe as:
  243. %windir%\system32\dxdiag.exe
  244. --*/
  245. BOOL
  246. StubDxDiag(
  247. CString& csNewApplicationName,
  248. CString& csNewCommandLine,
  249. BOOL bExists
  250. )
  251. {
  252. csNewApplicationName = g_szSysDir;
  253. csNewApplicationName += L"\\dxdiag.exe";
  254. csNewCommandLine = L"";
  255. return TRUE;
  256. }
  257. /*++
  258. We are here because the application name: Winhlp.exe, matches the one in the
  259. static array. Fill the News for .exe as:
  260. %windir%\system32\winhlp32.exe
  261. --*/
  262. BOOL
  263. StubWinhlp(
  264. CString& csNewApplicationName,
  265. CString& csNewCommandLine,
  266. BOOL bExists
  267. )
  268. {
  269. csNewApplicationName = g_szSysDir;
  270. csNewApplicationName += L"\\winhlp32.exe";
  271. // Winhlp32.exe needs the app name to be in the commandline.
  272. csNewCommandLine = csNewApplicationName;
  273. return TRUE;
  274. }
  275. /*++
  276. We are here because the application name: rundll.exe matches the one in the
  277. static array. Fill the News for .exe as:
  278. %windir%\system32\rundll32.exe
  279. --*/
  280. BOOL
  281. StubRundll(
  282. CString& csNewApplicationName,
  283. CString& csNewCommandLine,
  284. BOOL bExists
  285. )
  286. {
  287. csNewApplicationName = g_szSysDir;
  288. csNewApplicationName += L"\\rundll32.exe";
  289. csNewCommandLine = L"";
  290. return TRUE;
  291. }
  292. /*++
  293. We are here because the application name: Pbrush.exe matches the one in the
  294. static array. Fill the New for .exe as:
  295. %windir%\system32\mspaint.exe
  296. --*/
  297. BOOL
  298. StubPbrush(
  299. CString& csNewApplicationName,
  300. CString& csNewCommandLine,
  301. BOOL bExists
  302. )
  303. {
  304. csNewApplicationName = g_szSysDir;
  305. csNewApplicationName += L"\\mspaint.exe";
  306. csNewCommandLine = L"";
  307. return TRUE;
  308. }
  309. /*++
  310. GetTitle takes the app path and returns just the EXE name.
  311. --*/
  312. VOID
  313. GetTitle(CString& csAppName,CString& csAppTitle)
  314. {
  315. csAppTitle = csAppName;
  316. int len = csAppName.ReverseFind(L'\\');
  317. if (len)
  318. {
  319. csAppTitle.Delete(0, len+1);
  320. }
  321. }
  322. /*++
  323. This is the main function where the New logic happens. This function
  324. goes through the static array and fills the suitable New appname and
  325. the commandline.
  326. --*/
  327. BOOL
  328. Redirect(
  329. const CString& csApplicationName,
  330. const CString& csCommandLine,
  331. CString& csNewApplicationName,
  332. CString& csNewCommandLine,
  333. BOOL bJustCheckExePresence
  334. )
  335. {
  336. BOOL bRet = FALSE;
  337. CSTRING_TRY
  338. {
  339. CString csOrigAppName;
  340. CString csOrigCommandLine;
  341. BOOL bExists = FALSE;
  342. AppAndCommandLine AppObj(csApplicationName, csCommandLine);
  343. csOrigAppName = AppObj.GetApplicationName();
  344. csOrigCommandLine = AppObj.GetCommandlineNoAppName();
  345. if (csOrigAppName.IsEmpty())
  346. {
  347. goto Exit;
  348. }
  349. //
  350. // Loop through the list of redirectors
  351. //
  352. REPLACEENTRY *rEntry = &g_ReplList[0];
  353. CString csAppTitle;
  354. GetTitle(csOrigAppName, csAppTitle);
  355. while (rEntry && rEntry->OrigExeName[0])
  356. {
  357. if (_wcsicmp(rEntry->OrigExeName, csAppTitle) == 0)
  358. {
  359. //
  360. // This final parameter has been added for the merger
  361. // of HandleStartKeyword Shim. If this is TRUE, we don't
  362. // go any further but just return.
  363. //
  364. if (bJustCheckExePresence)
  365. {
  366. bRet = TRUE;
  367. goto Exit;
  368. }
  369. //
  370. // Check if the current working directory contains the exe in question
  371. //
  372. WCHAR szCurrentDirectory[MAX_PATH];
  373. if (szCurrentDirectory &&
  374. GetCurrentDirectoryW(MAX_PATH, szCurrentDirectory))
  375. {
  376. CString csFullAppName(szCurrentDirectory);
  377. csFullAppName += L"\\";
  378. csFullAppName += csAppTitle;
  379. // Check if the file exists and is not a directory
  380. DWORD dwAttr = GetFileAttributesW(csFullAppName);
  381. if ((dwAttr != 0xFFFFFFFF) &&
  382. !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  383. {
  384. DPFN( eDbgLevelInfo,
  385. "[Redirect] %s found in current working directory");
  386. bExists = TRUE;
  387. }
  388. }
  389. //
  390. // We have a match, so call the corresponding function
  391. //
  392. if (bRet = (*(rEntry->pfnFuncName))(csNewApplicationName,
  393. csNewCommandLine, bExists))
  394. {
  395. //
  396. // Append the original command line
  397. //
  398. csNewCommandLine += L" ";
  399. csNewCommandLine += csOrigCommandLine;
  400. }
  401. // We matched an EXE, so we're done
  402. break;
  403. }
  404. rEntry++;
  405. }
  406. if (bRet)
  407. {
  408. DPFN( eDbgLevelWarning, "Redirected:");
  409. DPFN( eDbgLevelWarning, "\tFrom: %S %S", csApplicationName, csCommandLine);
  410. DPFN( eDbgLevelWarning, "\tTo: %S %S", csNewApplicationName, csNewCommandLine);
  411. }
  412. }
  413. CSTRING_CATCH
  414. {
  415. DPFN( eDbgLevelError, "Not Redirecting: Exception encountered");
  416. bRet = FALSE;
  417. }
  418. Exit:
  419. return bRet;
  420. }
  421. /*++
  422. Hooks the CreateProcessA function to see if any News need to be
  423. substituted.
  424. --*/
  425. BOOL
  426. APIHOOK(CreateProcessA)(
  427. LPCSTR lpApplicationName,
  428. LPSTR lpCommandLine,
  429. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  430. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  431. BOOL bInheritHandles,
  432. DWORD dwCreationFlags,
  433. LPVOID lpEnvironment,
  434. LPCSTR lpCurrentDirectory,
  435. LPSTARTUPINFOA lpStartupInfo,
  436. LPPROCESS_INFORMATION lpProcessInformation
  437. )
  438. {
  439. if ((NULL == lpApplicationName) &&
  440. (NULL == lpCommandLine))
  441. {
  442. // If both are NULL, return FALSE.
  443. SetLastError(ERROR_INVALID_PARAMETER);
  444. return FALSE;
  445. }
  446. CSTRING_TRY
  447. {
  448. CString csNewApplicationName;
  449. CString csNewCommandLine;
  450. CString csPassedAppName(lpApplicationName);
  451. CString csPassedCommandLine(lpCommandLine);
  452. if ((csPassedAppName.IsEmpty()) &&
  453. (csPassedCommandLine.IsEmpty()))
  454. {
  455. goto exit;
  456. }
  457. //
  458. // Run the list of New stubs: call to the main New routine
  459. //
  460. if (Redirect(csPassedAppName, csPassedCommandLine, csNewApplicationName,
  461. csNewCommandLine, FALSE))
  462. {
  463. LOGN(
  464. eDbgLevelWarning,
  465. "[CreateProcessA] \" %s %s \": changed to \" %s %s \"",
  466. lpApplicationName, lpCommandLine,
  467. csNewApplicationName.GetAnsi(), csNewCommandLine.GetAnsi());
  468. }
  469. else
  470. {
  471. csNewApplicationName = lpApplicationName;
  472. csNewCommandLine = lpCommandLine;
  473. }
  474. // Convert back to ANSI using the GetAnsi() method exposed by the CString class.
  475. return ORIGINAL_API(CreateProcessA)(
  476. csNewApplicationName.IsEmpty() ? NULL : csNewApplicationName.GetAnsi(),
  477. csNewCommandLine.IsEmpty() ? NULL : csNewCommandLine.GetAnsi(),
  478. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  479. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  480. lpProcessInformation);
  481. }
  482. CSTRING_CATCH
  483. {
  484. DPFN( eDbgLevelError, "[CreateProcessA]:Original API called.Exception occured!");
  485. }
  486. exit:
  487. return ORIGINAL_API(CreateProcessA)(lpApplicationName, lpCommandLine,
  488. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  489. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  490. lpProcessInformation);
  491. }
  492. /*++
  493. Hooks the CreateProcessW function to see if any News need to be
  494. substituted.
  495. --*/
  496. BOOL
  497. APIHOOK(CreateProcessW)(
  498. LPCWSTR lpApplicationName,
  499. LPWSTR lpCommandLine,
  500. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  501. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  502. BOOL bInheritHandles,
  503. DWORD dwCreationFlags,
  504. LPVOID lpEnvironment,
  505. LPCWSTR lpCurrentDirectory,
  506. LPSTARTUPINFOW lpStartupInfo,
  507. LPPROCESS_INFORMATION lpProcessInformation
  508. )
  509. {
  510. if ((NULL == lpApplicationName) &&
  511. (NULL == lpCommandLine))
  512. {
  513. // If both are NULL, return FALSE.
  514. SetLastError(ERROR_INVALID_PARAMETER);
  515. return FALSE;
  516. }
  517. CSTRING_TRY
  518. {
  519. CString csNewApplicationName;
  520. CString csNewCommandLine;
  521. CString csApplicationName(lpApplicationName);
  522. CString csCommandLine(lpCommandLine);
  523. if ((csApplicationName.IsEmpty()) &&
  524. (csCommandLine.IsEmpty()))
  525. {
  526. goto exit;
  527. }
  528. //
  529. // Run the list of New stubs
  530. //
  531. if (Redirect(csApplicationName, csCommandLine, csNewApplicationName,
  532. csNewCommandLine, FALSE))
  533. {
  534. LOGN(
  535. eDbgLevelWarning,
  536. "[CreateProcessW] \" %S %S \": changed to \" %S %S \"",
  537. lpApplicationName, lpCommandLine, csNewApplicationName, csNewCommandLine);
  538. }
  539. else
  540. {
  541. csNewApplicationName = lpApplicationName;
  542. csNewCommandLine = lpCommandLine;
  543. }
  544. return ORIGINAL_API(CreateProcessW)(
  545. csNewApplicationName.IsEmpty() ? NULL : csNewApplicationName.Get(),
  546. csNewCommandLine.IsEmpty() ? NULL : (LPWSTR)csNewCommandLine.Get(),
  547. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  548. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  549. lpProcessInformation);
  550. }
  551. CSTRING_CATCH
  552. {
  553. DPFN( eDbgLevelError, "[CreateProcessW] Original API called. Exception occured!");
  554. }
  555. exit:
  556. return ORIGINAL_API(CreateProcessW)(lpApplicationName, lpCommandLine,
  557. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  558. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  559. lpProcessInformation);
  560. }
  561. /*++
  562. Hooks WinExec to redirect if necessary.
  563. --*/
  564. UINT
  565. APIHOOK(WinExec)(
  566. LPCSTR lpCmdLine,
  567. UINT uCmdShow
  568. )
  569. {
  570. if (NULL == lpCmdLine)
  571. {
  572. SetLastError(ERROR_INVALID_PARAMETER);
  573. return ERROR_PATH_NOT_FOUND;
  574. }
  575. CSTRING_TRY
  576. {
  577. CString csNewApplicationName;
  578. CString csNewCommandLine;
  579. CString csAppName;
  580. CString csNewCmdLine;
  581. CString csCommandLine(lpCmdLine);
  582. if (csCommandLine.IsEmpty())
  583. {
  584. goto exit;
  585. }
  586. // Check for redirection
  587. if (Redirect(csAppName, csCommandLine, csNewApplicationName,
  588. csNewCommandLine, FALSE))
  589. {
  590. // Modification for the WinHlp32 strange behaviour
  591. if (csNewCommandLine.Find(csNewApplicationName.Get()) == -1)
  592. {
  593. // If the new Command line does not contain the new application
  594. // name as the substring, we are here.
  595. csNewCmdLine = csNewApplicationName;
  596. csNewCmdLine += L" ";
  597. }
  598. csNewCmdLine += csNewCommandLine;
  599. // Assign to csCommandLine as this can be commonly used
  600. csCommandLine = csNewCmdLine;
  601. LOGN(
  602. eDbgLevelInfo,
  603. "[WinExec] \" %s \": changed to \" %s \"",
  604. lpCmdLine, csCommandLine.GetAnsi());
  605. }
  606. return ORIGINAL_API(WinExec)(csCommandLine.GetAnsi(), uCmdShow);
  607. }
  608. CSTRING_CATCH
  609. {
  610. DPFN( eDbgLevelError, "[WinExec]:Original API called.Exception occured!");
  611. }
  612. exit:
  613. return ORIGINAL_API(WinExec)(lpCmdLine, uCmdShow);
  614. }
  615. /*++
  616. Hooks the FindFirstFileA function to see if any replacements need to be
  617. substituted. This is a requirement for cmd.exe.
  618. --*/
  619. HANDLE
  620. APIHOOK(FindFirstFileA)(
  621. LPCSTR lpFileName,
  622. LPWIN32_FIND_DATAA lpFindFileData
  623. )
  624. {
  625. CSTRING_TRY
  626. {
  627. CString csNewApplicationName;
  628. CString csNewCommandLine;
  629. CString csFileName(lpFileName);
  630. CString csAppName;
  631. // Call the main replacement routine.
  632. if (Redirect(csFileName, csAppName, csNewApplicationName, csNewCommandLine, FALSE))
  633. {
  634. // Assign to csFileName
  635. csFileName = csNewApplicationName;
  636. LOGN(
  637. eDbgLevelInfo,
  638. "[FindFirstFileA] \" %s \": changed to \" %s \"",
  639. lpFileName, csFileName.GetAnsi());
  640. }
  641. return ORIGINAL_API(FindFirstFileA)(csFileName.GetAnsi(), lpFindFileData);
  642. }
  643. CSTRING_CATCH
  644. {
  645. DPFN( eDbgLevelError, "[FindFirstFileA]:Original API called.Exception occured!");
  646. return ORIGINAL_API(FindFirstFileA)(lpFileName, lpFindFileData);
  647. }
  648. }
  649. /*++
  650. Hooks the FindFirstFileW function to see if any replacements need to be
  651. substituted. This is a requirement for cmd.exe.
  652. --*/
  653. HANDLE
  654. APIHOOK(FindFirstFileW)(
  655. LPCWSTR lpFileName,
  656. LPWIN32_FIND_DATAW lpFindFileData
  657. )
  658. {
  659. CSTRING_TRY
  660. {
  661. CString csNewApplicationName(lpFileName);
  662. CString csNewCommandLine;
  663. CString csFileName(lpFileName);
  664. CString csAppName;
  665. // Call the main replacement routine.
  666. if (Redirect(csFileName, csAppName, csNewApplicationName,
  667. csNewCommandLine, FALSE))
  668. {
  669. LOGN(
  670. eDbgLevelInfo,
  671. "[FindFirstFileW] \" %S \": changed to \" %S \"",
  672. lpFileName, (const WCHAR*)csNewApplicationName);
  673. }
  674. return ORIGINAL_API(FindFirstFileW)(csNewApplicationName, lpFindFileData);
  675. }
  676. CSTRING_CATCH
  677. {
  678. DPFN( eDbgLevelError, "[FindFirstFileW]:Original API called.Exception occured!");
  679. return ORIGINAL_API(FindFirstFileW)(lpFileName, lpFindFileData);
  680. }
  681. }
  682. // Added for the merge of HandleStartKeyword
  683. /*++
  684. Hook IShellLinkA::SetPath - check if it's start, if so change it to cmd and add the
  685. this pointer to the list.
  686. --*/
  687. HRESULT STDMETHODCALLTYPE
  688. COMHOOK(IShellLinkA, SetPath)(
  689. PVOID pThis,
  690. LPCSTR pszFile
  691. )
  692. {
  693. _pfn_IShellLinkA_SetPath pfnSetPath = ORIGINAL_COM( IShellLinkA, SetPath, pThis);
  694. CSTRING_TRY
  695. {
  696. CString csExeName;
  697. CString csCmdLine;
  698. CString csNewAppName;
  699. CString csNewCmdLine;
  700. CString cscmdCommandLine(pszFile);
  701. // Assign the ANSI string to the WCHAR CString
  702. csExeName = pszFile;
  703. csExeName.TrimLeft();
  704. // Check to see whether the Filename conatains the "Start" keyword.
  705. // The last parameter to the Rediect function controls this.
  706. if (Redirect(csExeName, csCmdLine, csNewAppName, csNewCmdLine, TRUE))
  707. {
  708. // Found a match. We add the this pointer to the list.
  709. AddThisPointer(pThis);
  710. DPFN( eDbgLevelInfo, "[SetPath] Changing start.exe to cmd.exe\n");
  711. // Prefix of new "start" command line, use full path to CMD.EXE
  712. // Append the WCHAR global system directory path to ANSI CString
  713. cscmdCommandLine = g_szSysDir;
  714. cscmdCommandLine += L"\\cmd.exe";
  715. }
  716. return (*pfnSetPath)(pThis, cscmdCommandLine.GetAnsi());
  717. }
  718. CSTRING_CATCH
  719. {
  720. DPFN( eDbgLevelError, "[SetPath] Original API called. Exception occured!");
  721. return (*pfnSetPath)(pThis, pszFile);
  722. }
  723. }
  724. /*++
  725. Hook IShellLinkA::SetArguments - if the this pointer can be found in the list, remove it
  726. from the list and add "/d /c start" in front of the original argument list.
  727. --*/
  728. HRESULT STDMETHODCALLTYPE
  729. COMHOOK(IShellLinkA, SetArguments)(
  730. PVOID pThis,
  731. LPCSTR pszFile
  732. )
  733. {
  734. _pfn_IShellLinkA_SetArguments pfnSetArguments = ORIGINAL_COM(IShellLinkA, SetArguments, pThis);
  735. CSTRING_TRY
  736. {
  737. CString csNewFile(pszFile);
  738. if (RemoveThisPointer(pThis))
  739. {
  740. csNewFile = "/d /c start \"\" ";
  741. csNewFile += pszFile;
  742. DPFN( eDbgLevelInfo, "[SetArguments] Arg list is now %S", csNewFile);
  743. }
  744. return (*pfnSetArguments)( pThis, csNewFile.GetAnsi());
  745. }
  746. CSTRING_CATCH
  747. {
  748. DPFN( eDbgLevelError, "[SetArguments]:Original API called.Exception occured!");
  749. return (*pfnSetArguments)( pThis, pszFile );
  750. }
  751. }
  752. /*++
  753. Register hooked functions
  754. --*/
  755. BOOL
  756. NOTIFY_FUNCTION(
  757. DWORD fdwReason
  758. )
  759. {
  760. if (fdwReason == DLL_PROCESS_ATTACH)
  761. {
  762. if (!GetSystemDirectory(g_szSysDir, MAX_PATH))
  763. {
  764. DPFN( eDbgLevelError, "[Notify] GetSystemDirectory failed");
  765. return FALSE;
  766. }
  767. InitializeCriticalSection(&g_CritSec);
  768. }
  769. return TRUE;
  770. }
  771. HOOK_BEGIN
  772. CALL_NOTIFY_FUNCTION
  773. APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessA)
  774. APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessW)
  775. APIHOOK_ENTRY(KERNEL32.DLL, WinExec)
  776. APIHOOK_ENTRY(KERNEL32.DLL, FindFirstFileA)
  777. APIHOOK_ENTRY(KERNEL32.DLL, FindFirstFileW)
  778. APIHOOK_ENTRY_COMSERVER(SHELL32)
  779. COMHOOK_ENTRY(ShellLink, IShellLinkA, SetPath, 20)
  780. COMHOOK_ENTRY(ShellLink, IShellLinkA, SetArguments, 11)
  781. HOOK_END
  782. IMPLEMENT_SHIM_END