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.

1003 lines
26 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 = NULL; // 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 = NULL;
  373. DWORD dwLen = GetCurrentDirectoryW(0, NULL); // Just to get the length
  374. // The dwLen got includes the terminating NULL too.
  375. szCurrentDirectory = (WCHAR*)malloc(dwLen * sizeof(WCHAR));
  376. if (szCurrentDirectory &&
  377. GetCurrentDirectoryW(dwLen, szCurrentDirectory))
  378. {
  379. CString csFullAppName(szCurrentDirectory);
  380. csFullAppName += L"\\";
  381. csFullAppName += csAppTitle;
  382. // Check if the file exists and is not a directory
  383. DWORD dwAttr = GetFileAttributesW(csFullAppName);
  384. if ((dwAttr != INVALID_FILE_ATTRIBUTES) &&
  385. !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
  386. {
  387. DPFN( eDbgLevelInfo,
  388. "[Redirect] %s found in current working directory");
  389. bExists = TRUE;
  390. }
  391. free(szCurrentDirectory);
  392. }
  393. else if(szCurrentDirectory)
  394. {
  395. free(szCurrentDirectory);
  396. }
  397. //
  398. // We have a match, so call the corresponding function
  399. //
  400. bRet = (*(rEntry->pfnFuncName))(csNewApplicationName,
  401. csNewCommandLine, bExists);
  402. if (bRet)
  403. {
  404. //
  405. // Append the original command line
  406. //
  407. csNewCommandLine += L" ";
  408. csNewCommandLine += csOrigCommandLine;
  409. }
  410. // We matched an EXE, so we're done
  411. break;
  412. }
  413. rEntry++;
  414. }
  415. if (bRet)
  416. {
  417. DPFN( eDbgLevelWarning, "Redirected:");
  418. DPFN( eDbgLevelWarning, "\tFrom: %S %S", csApplicationName, csCommandLine);
  419. DPFN( eDbgLevelWarning, "\tTo: %S %S", csNewApplicationName, csNewCommandLine);
  420. }
  421. }
  422. CSTRING_CATCH
  423. {
  424. DPFN( eDbgLevelError, "Not Redirecting: Exception encountered");
  425. bRet = FALSE;
  426. }
  427. Exit:
  428. return bRet;
  429. }
  430. /*++
  431. Hooks the CreateProcessA function to see if any News need to be
  432. substituted.
  433. --*/
  434. BOOL
  435. APIHOOK(CreateProcessA)(
  436. LPCSTR lpApplicationName,
  437. LPSTR lpCommandLine,
  438. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  439. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  440. BOOL bInheritHandles,
  441. DWORD dwCreationFlags,
  442. LPVOID lpEnvironment,
  443. LPCSTR lpCurrentDirectory,
  444. LPSTARTUPINFOA lpStartupInfo,
  445. LPPROCESS_INFORMATION lpProcessInformation
  446. )
  447. {
  448. if ((NULL == lpApplicationName) &&
  449. (NULL == lpCommandLine))
  450. {
  451. // If both are NULL, return FALSE.
  452. SetLastError(ERROR_INVALID_PARAMETER);
  453. return FALSE;
  454. }
  455. CSTRING_TRY
  456. {
  457. CString csNewApplicationName;
  458. CString csNewCommandLine;
  459. CString csPassedAppName(lpApplicationName);
  460. CString csPassedCommandLine(lpCommandLine);
  461. if ((csPassedAppName.IsEmpty()) &&
  462. (csPassedCommandLine.IsEmpty()))
  463. {
  464. goto exit;
  465. }
  466. //
  467. // Run the list of New stubs: call to the main New routine
  468. //
  469. if (Redirect(csPassedAppName, csPassedCommandLine, csNewApplicationName,
  470. csNewCommandLine, FALSE))
  471. {
  472. LOGN(
  473. eDbgLevelWarning,
  474. "[CreateProcessA] \" %s %s \": changed to \" %s %s \"",
  475. lpApplicationName, lpCommandLine,
  476. csNewApplicationName.GetAnsi(), csNewCommandLine.GetAnsi());
  477. }
  478. else
  479. {
  480. csNewApplicationName = lpApplicationName;
  481. csNewCommandLine = lpCommandLine;
  482. }
  483. // Convert back to ANSI using the GetAnsi() method exposed by the CString class.
  484. return ORIGINAL_API(CreateProcessA)(
  485. csNewApplicationName.IsEmpty() ? NULL : csNewApplicationName.GetAnsi(),
  486. csNewCommandLine.IsEmpty() ? NULL : csNewCommandLine.GetAnsi(),
  487. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  488. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  489. lpProcessInformation);
  490. }
  491. CSTRING_CATCH
  492. {
  493. DPFN( eDbgLevelError, "[CreateProcessA]:Original API called.Exception occured!");
  494. }
  495. exit:
  496. return ORIGINAL_API(CreateProcessA)(lpApplicationName, lpCommandLine,
  497. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  498. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  499. lpProcessInformation);
  500. }
  501. /*++
  502. Hooks the CreateProcessW function to see if any News need to be
  503. substituted.
  504. --*/
  505. BOOL
  506. APIHOOK(CreateProcessW)(
  507. LPCWSTR lpApplicationName,
  508. LPWSTR lpCommandLine,
  509. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  510. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  511. BOOL bInheritHandles,
  512. DWORD dwCreationFlags,
  513. LPVOID lpEnvironment,
  514. LPCWSTR lpCurrentDirectory,
  515. LPSTARTUPINFOW lpStartupInfo,
  516. LPPROCESS_INFORMATION lpProcessInformation
  517. )
  518. {
  519. if ((NULL == lpApplicationName) &&
  520. (NULL == lpCommandLine))
  521. {
  522. // If both are NULL, return FALSE.
  523. SetLastError(ERROR_INVALID_PARAMETER);
  524. return FALSE;
  525. }
  526. CSTRING_TRY
  527. {
  528. CString csNewApplicationName;
  529. CString csNewCommandLine;
  530. CString csApplicationName(lpApplicationName);
  531. CString csCommandLine(lpCommandLine);
  532. if ((csApplicationName.IsEmpty()) &&
  533. (csCommandLine.IsEmpty()))
  534. {
  535. goto exit;
  536. }
  537. //
  538. // Run the list of New stubs
  539. //
  540. if (Redirect(csApplicationName, csCommandLine, csNewApplicationName,
  541. csNewCommandLine, FALSE))
  542. {
  543. LOGN(
  544. eDbgLevelWarning,
  545. "[CreateProcessW] \" %S %S \": changed to \" %S %S \"",
  546. lpApplicationName, lpCommandLine, csNewApplicationName, csNewCommandLine);
  547. }
  548. else
  549. {
  550. csNewApplicationName = lpApplicationName;
  551. csNewCommandLine = lpCommandLine;
  552. }
  553. return ORIGINAL_API(CreateProcessW)(
  554. csNewApplicationName.IsEmpty() ? NULL : csNewApplicationName.Get(),
  555. csNewCommandLine.IsEmpty() ? NULL : (LPWSTR)csNewCommandLine.Get(),
  556. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  557. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  558. lpProcessInformation);
  559. }
  560. CSTRING_CATCH
  561. {
  562. DPFN( eDbgLevelError, "[CreateProcessW] Original API called. Exception occured!");
  563. }
  564. exit:
  565. return ORIGINAL_API(CreateProcessW)(lpApplicationName, lpCommandLine,
  566. lpProcessAttributes, lpThreadAttributes, bInheritHandles,
  567. dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo,
  568. lpProcessInformation);
  569. }
  570. /*++
  571. Hooks WinExec to redirect if necessary.
  572. --*/
  573. UINT
  574. APIHOOK(WinExec)(
  575. LPCSTR lpCmdLine,
  576. UINT uCmdShow
  577. )
  578. {
  579. if (NULL == lpCmdLine)
  580. {
  581. SetLastError(ERROR_INVALID_PARAMETER);
  582. return ERROR_PATH_NOT_FOUND;
  583. }
  584. CSTRING_TRY
  585. {
  586. CString csNewApplicationName;
  587. CString csNewCommandLine;
  588. CString csAppName;
  589. CString csNewCmdLine;
  590. CString csCommandLine(lpCmdLine);
  591. if (csCommandLine.IsEmpty())
  592. {
  593. goto exit;
  594. }
  595. // Check for redirection
  596. if (Redirect(csAppName, csCommandLine, csNewApplicationName,
  597. csNewCommandLine, FALSE))
  598. {
  599. // Modification for the WinHlp32 strange behaviour
  600. if (csNewCommandLine.Find(csNewApplicationName.Get()) == -1)
  601. {
  602. // If the new Command line does not contain the new application
  603. // name as the substring, we are here.
  604. csNewCmdLine = csNewApplicationName;
  605. csNewCmdLine += L" ";
  606. }
  607. csNewCmdLine += csNewCommandLine;
  608. // Assign to csCommandLine as this can be commonly used
  609. csCommandLine = csNewCmdLine;
  610. LOGN(
  611. eDbgLevelInfo,
  612. "[WinExec] \" %s \": changed to \" %s \"",
  613. lpCmdLine, csCommandLine.GetAnsi());
  614. }
  615. return ORIGINAL_API(WinExec)(csCommandLine.GetAnsi(), uCmdShow);
  616. }
  617. CSTRING_CATCH
  618. {
  619. DPFN( eDbgLevelError, "[WinExec]:Original API called.Exception occured!");
  620. }
  621. exit:
  622. return ORIGINAL_API(WinExec)(lpCmdLine, uCmdShow);
  623. }
  624. /*++
  625. Hooks the FindFirstFileA function to see if any replacements need to be
  626. substituted. This is a requirement for cmd.exe.
  627. --*/
  628. HANDLE
  629. APIHOOK(FindFirstFileA)(
  630. LPCSTR lpFileName,
  631. LPWIN32_FIND_DATAA lpFindFileData
  632. )
  633. {
  634. CSTRING_TRY
  635. {
  636. CString csNewApplicationName;
  637. CString csNewCommandLine;
  638. CString csFileName(lpFileName);
  639. CString csAppName;
  640. // Call the main replacement routine.
  641. if (Redirect(csFileName, csAppName, csNewApplicationName, csNewCommandLine, FALSE))
  642. {
  643. // Assign to csFileName
  644. csFileName = csNewApplicationName;
  645. LOGN(
  646. eDbgLevelInfo,
  647. "[FindFirstFileA] \" %s \": changed to \" %s \"",
  648. lpFileName, csFileName.GetAnsi());
  649. }
  650. return ORIGINAL_API(FindFirstFileA)(csFileName.GetAnsi(), lpFindFileData);
  651. }
  652. CSTRING_CATCH
  653. {
  654. DPFN( eDbgLevelError, "[FindFirstFileA]:Original API called.Exception occured!");
  655. return ORIGINAL_API(FindFirstFileA)(lpFileName, lpFindFileData);
  656. }
  657. }
  658. /*++
  659. Hooks the FindFirstFileW function to see if any replacements need to be
  660. substituted. This is a requirement for cmd.exe.
  661. --*/
  662. HANDLE
  663. APIHOOK(FindFirstFileW)(
  664. LPCWSTR lpFileName,
  665. LPWIN32_FIND_DATAW lpFindFileData
  666. )
  667. {
  668. CSTRING_TRY
  669. {
  670. CString csNewApplicationName(lpFileName);
  671. CString csNewCommandLine;
  672. CString csFileName(lpFileName);
  673. CString csAppName;
  674. // Call the main replacement routine.
  675. if (Redirect(csFileName, csAppName, csNewApplicationName,
  676. csNewCommandLine, FALSE))
  677. {
  678. LOGN(
  679. eDbgLevelInfo,
  680. "[FindFirstFileW] \" %S \": changed to \" %S \"",
  681. lpFileName, (const WCHAR*)csNewApplicationName);
  682. }
  683. return ORIGINAL_API(FindFirstFileW)(csNewApplicationName, lpFindFileData);
  684. }
  685. CSTRING_CATCH
  686. {
  687. DPFN( eDbgLevelError, "[FindFirstFileW]:Original API called.Exception occured!");
  688. return ORIGINAL_API(FindFirstFileW)(lpFileName, lpFindFileData);
  689. }
  690. }
  691. // Added for the merge of HandleStartKeyword
  692. /*++
  693. Hook IShellLinkA::SetPath - check if it's start, if so change it to cmd and add the
  694. this pointer to the list.
  695. --*/
  696. HRESULT STDMETHODCALLTYPE
  697. COMHOOK(IShellLinkA, SetPath)(
  698. PVOID pThis,
  699. LPCSTR pszFile
  700. )
  701. {
  702. _pfn_IShellLinkA_SetPath pfnSetPath = ORIGINAL_COM( IShellLinkA, SetPath, pThis);
  703. CSTRING_TRY
  704. {
  705. CString csExeName;
  706. CString csCmdLine;
  707. CString csNewAppName;
  708. CString csNewCmdLine;
  709. CString cscmdCommandLine(pszFile);
  710. // Assign the ANSI string to the WCHAR CString
  711. csExeName = pszFile;
  712. csExeName.TrimLeft();
  713. // Check to see whether the Filename conatains the "Start" keyword.
  714. // The last parameter to the Rediect function controls this.
  715. if (Redirect(csExeName, csCmdLine, csNewAppName, csNewCmdLine, TRUE))
  716. {
  717. // Found a match. We add the this pointer to the list.
  718. AddThisPointer(pThis);
  719. DPFN( eDbgLevelInfo, "[SetPath] Changing start.exe to cmd.exe\n");
  720. // Prefix of new "start" command line, use full path to CMD.EXE
  721. // Append the WCHAR global system directory path to ANSI CString
  722. cscmdCommandLine = g_szSysDir;
  723. cscmdCommandLine += L"\\cmd.exe";
  724. }
  725. return (*pfnSetPath)(pThis, cscmdCommandLine.GetAnsi());
  726. }
  727. CSTRING_CATCH
  728. {
  729. DPFN( eDbgLevelError, "[SetPath] Original API called. Exception occured!");
  730. return (*pfnSetPath)(pThis, pszFile);
  731. }
  732. }
  733. /*++
  734. Hook IShellLinkA::SetArguments - if the this pointer can be found in the list, remove it
  735. from the list and add "/d /c start" in front of the original argument list.
  736. --*/
  737. HRESULT STDMETHODCALLTYPE
  738. COMHOOK(IShellLinkA, SetArguments)(
  739. PVOID pThis,
  740. LPCSTR pszFile
  741. )
  742. {
  743. _pfn_IShellLinkA_SetArguments pfnSetArguments = ORIGINAL_COM(IShellLinkA, SetArguments, pThis);
  744. CSTRING_TRY
  745. {
  746. CString csNewFile(pszFile);
  747. if (RemoveThisPointer(pThis))
  748. {
  749. csNewFile = "/d /c start \"\" ";
  750. csNewFile += pszFile;
  751. DPFN( eDbgLevelInfo, "[SetArguments] Arg list is now %S", csNewFile);
  752. }
  753. return (*pfnSetArguments)( pThis, csNewFile.GetAnsi());
  754. }
  755. CSTRING_CATCH
  756. {
  757. DPFN( eDbgLevelError, "[SetArguments]:Original API called.Exception occured!");
  758. return (*pfnSetArguments)( pThis, pszFile );
  759. }
  760. }
  761. /*++
  762. Register hooked functions
  763. --*/
  764. BOOL
  765. NOTIFY_FUNCTION(
  766. DWORD fdwReason
  767. )
  768. {
  769. if (fdwReason == DLL_PROCESS_ATTACH)
  770. {
  771. UINT uiLen = GetSystemDirectory(NULL, 0);
  772. g_szSysDir = (WCHAR*)malloc(uiLen * sizeof(WCHAR)); // This won't be deallocated..
  773. if (g_szSysDir && !GetSystemDirectory(g_szSysDir, uiLen))
  774. {
  775. DPFN( eDbgLevelError, "[Notify] GetSystemDirectory failed");
  776. return FALSE;
  777. }
  778. if (InitializeCriticalSectionAndSpinCount(&g_CritSec, 0x80000000) == FALSE)
  779. {
  780. DPFN( eDbgLevelError, "Failed to initialize critical section");
  781. return FALSE;
  782. }
  783. }
  784. return TRUE;
  785. }
  786. HOOK_BEGIN
  787. CALL_NOTIFY_FUNCTION
  788. APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessA)
  789. APIHOOK_ENTRY(KERNEL32.DLL, CreateProcessW)
  790. APIHOOK_ENTRY(KERNEL32.DLL, WinExec)
  791. APIHOOK_ENTRY(KERNEL32.DLL, FindFirstFileA)
  792. APIHOOK_ENTRY(KERNEL32.DLL, FindFirstFileW)
  793. APIHOOK_ENTRY_COMSERVER(SHELL32)
  794. COMHOOK_ENTRY(ShellLink, IShellLinkA, SetPath, 20)
  795. COMHOOK_ENTRY(ShellLink, IShellLinkA, SetArguments, 11)
  796. HOOK_END
  797. IMPLEMENT_SHIM_END