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.

1394 lines
35 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. Badfunc.cpp
  5. Abstract:
  6. Contains all the bad functions. These are the functions
  7. that will have Compatibility Fixes applied.
  8. Notes:
  9. ANSI only - must run on Win9x.
  10. History:
  11. 01/30/01 rparsons Created
  12. 01/10/02 rparsons Revised
  13. 02/13/02 rparsons Use strsafe functions
  14. --*/
  15. #include "demoapp.h"
  16. extern APPINFO g_ai;
  17. //
  18. // Pointer to the exported function that we get from our DLL.
  19. //
  20. LPFNDEMOAPPEXP DemoAppExpFunc;
  21. /*++
  22. Routine Description:
  23. Determines if we're running Windows 95.
  24. Arguments:
  25. None.
  26. Return Value:
  27. TRUE if we are, FALSE otherwise.
  28. --*/
  29. BOOL
  30. BadIsWindows95(
  31. void
  32. )
  33. {
  34. //
  35. // Most applications perform some sort of version check when they first
  36. // begin. This is usually okay, assuming they perform the check properly.
  37. // The problem is that instead of doing a greater than comparison, they
  38. // do an equal/not equal to. In other words, they look just for Win9x,
  39. // not Win9x or greater. Usually the application will function properly
  40. // on NT/2K/XP, so this check can be hooked and we can return NT/2K/XP
  41. // version info.
  42. //
  43. OSVERSIONINFO osvi;
  44. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  45. if (!GetVersionEx(&osvi)) {
  46. return FALSE;
  47. }
  48. //
  49. // Check for Windows 9x (don't do a greater than).
  50. //
  51. if ((osvi.dwMajorVersion == 4) &&
  52. (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) {
  53. return TRUE;
  54. }
  55. return FALSE;
  56. }
  57. /*++
  58. Routine Description:
  59. Displays a debug message - this only happens on NT/Windows 2000/XP.
  60. Arguments:
  61. None.
  62. Return Value:
  63. None.
  64. --*/
  65. void
  66. BadLoadBogusDll(
  67. void
  68. )
  69. {
  70. //
  71. // Some applications will display a debug message under Windows NT/2000/XP.
  72. // For example, they try to locate a DLL that is available on Win9x, but
  73. // not on NT/2K/XP. If they don't find it, they'll complain, but will
  74. // most likely still work. In the example below, we try to find a function
  75. // in a DLL that would return TRUE on Win9x, but will fail on NT/2000/XP.
  76. //
  77. HRESULT hr;
  78. HINSTANCE hInstance;
  79. char szDll[MAX_PATH];
  80. const char szCvt32Dll[] = "cvt32.dll";
  81. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  82. hr = StringCchPrintf(szDll,
  83. sizeof(szDll),
  84. "%hs\\%hs",
  85. g_ai.szSysDir,
  86. szCvt32Dll);
  87. if (FAILED(hr)) {
  88. goto exit;
  89. }
  90. //
  91. // This will fail on NT/2K/XP because cvt32.dll doesn't exist on
  92. // these platforms. It will fail on Win9x/ME if the FAT32 conversion
  93. // tools are not installed.
  94. //
  95. hInstance = LoadLibrary(szDll);
  96. if (!hInstance) {
  97. MessageBox(g_ai.hWndMain,
  98. "Debug: Couldn't load CVT32.DLL.",
  99. 0,
  100. MB_ICONERROR);
  101. goto exit;
  102. }
  103. FreeLibrary(hInstance);
  104. exit:
  105. SetErrorMode(0);
  106. }
  107. /*++
  108. Routine Description:
  109. Apps call EnumPrinters using the PRINTER_ENUM_LOCAL flag,
  110. but expect to get back network printers also. This was a
  111. ***design feature*** in Windows 9x, but not in Windows 2000/XP.
  112. Arguments:
  113. None.
  114. Return Value:
  115. TRUE on success, FALSE otherwise.
  116. --*/
  117. BOOL
  118. BadEnumPrinters(
  119. void
  120. )
  121. {
  122. BOOL fReturn = FALSE;
  123. DWORD dwBytesNeeded = 0;
  124. DWORD dwNumReq = 0;
  125. DWORD dwLevel = 5;
  126. LPPRINTER_INFO_5 pPrtInfo = NULL;
  127. //
  128. // Get the required buffer size.
  129. //
  130. if (!EnumPrinters(PRINTER_ENUM_LOCAL,
  131. NULL,
  132. dwLevel,
  133. NULL,
  134. 0,
  135. &dwBytesNeeded,
  136. &dwNumReq)) {
  137. return FALSE;
  138. }
  139. pPrtInfo = (LPPRINTER_INFO_5)HeapAlloc(GetProcessHeap(),
  140. HEAP_ZERO_MEMORY,
  141. dwBytesNeeded);
  142. if (!pPrtInfo) {
  143. return FALSE;
  144. }
  145. //
  146. // Now perform the enumeration.
  147. //
  148. fReturn = EnumPrinters(PRINTER_ENUM_LOCAL, // types of printer objects to enumerate
  149. NULL, // name of printer object
  150. dwLevel, // specifies type of printer info structure
  151. (LPBYTE)pPrtInfo, // pointer to buffer to receive printer info structures
  152. dwBytesNeeded, // size, in bytes, of array
  153. &dwBytesNeeded, // pointer to variable with no. of bytes copied (or required)
  154. &dwNumReq); // pointer to variable with no. of printer info. structures copied
  155. HeapFree(GetProcessHeap(), 0, pPrtInfo);
  156. return fReturn;
  157. }
  158. /*++
  159. Routine Description:
  160. Apps call printer APIs passing NULL.
  161. Arguments:
  162. None.
  163. Return Value:
  164. A handle if we opened the printer successfully.
  165. --*/
  166. HANDLE
  167. BadOpenPrinter(
  168. void
  169. )
  170. {
  171. HANDLE hPrinter = NULL;
  172. OpenPrinter(NULL, &hPrinter, NULL);
  173. return hPrinter;
  174. }
  175. /*++
  176. Routine Description:
  177. Attempts to delete a registry key that has subkeys.
  178. Arguments:
  179. None.
  180. Return Value:
  181. TRUE on success, FALSE otherwise.
  182. --*/
  183. BOOL
  184. BadDeleteRegistryKey(
  185. void
  186. )
  187. {
  188. //
  189. // This function demonstrates a difference in the RegDeleteKey API.
  190. // If an application running on Windows NT/2000/XP attempts to
  191. // delete a key that has subkeys, the call will fail. This is not
  192. // the case on Windows 9x/ME.
  193. //
  194. HKEY hKey;
  195. HKEY hSubKey;
  196. HKEY hRootKey;
  197. LONG lReturn;
  198. //
  199. // Create the key or open it if it already exists.
  200. //
  201. lReturn = RegCreateKeyEx(HKEY_CURRENT_USER,
  202. DEMO_REG_APP_KEY, // Software\Microsoft\DemoApp2
  203. 0,
  204. 0,
  205. REG_OPTION_NON_VOLATILE,
  206. KEY_ALL_ACCESS,
  207. 0,
  208. &hKey,
  209. NULL);
  210. if (ERROR_SUCCESS != lReturn) {
  211. return FALSE;
  212. }
  213. //
  214. // Now create a subkey underneath the key was just created.
  215. //
  216. lReturn = RegCreateKeyEx(HKEY_CURRENT_USER,
  217. DEMO_REG_APP_SUB_KEY, // Software\Microsoft\DemoApp2\Sub
  218. 0,
  219. 0,
  220. REG_OPTION_NON_VOLATILE,
  221. KEY_ALL_ACCESS,
  222. 0,
  223. &hSubKey,
  224. NULL);
  225. if (ERROR_SUCCESS != lReturn) {
  226. RegCloseKey(hKey);
  227. return FALSE;
  228. }
  229. RegCloseKey(hKey);
  230. RegCloseKey(hSubKey);
  231. //
  232. // Open the key up, but one level higher.
  233. //
  234. lReturn = RegOpenKeyEx(HKEY_CURRENT_USER,
  235. DEMO_REG_APP_ROOT_KEY, // Software\Microsoft
  236. 0,
  237. KEY_ALL_ACCESS,
  238. &hRootKey);
  239. if (ERROR_SUCCESS != lReturn) {
  240. return FALSE;
  241. }
  242. //
  243. // Now try to delete our key.
  244. //
  245. lReturn = RegDeleteKey(hRootKey, "DemoApp2");
  246. RegCloseKey(hRootKey);
  247. return (lReturn == ERROR_SUCCESS ? TRUE : FALSE);
  248. }
  249. /*++
  250. Routine Description:
  251. Reboots the computer, if desired.
  252. Arguments:
  253. fReboot - A flag to indicate if the PC should be rebooted.
  254. Return Value:
  255. None.
  256. --*/
  257. void
  258. BadRebootComputer(
  259. IN BOOL fReboot
  260. )
  261. {
  262. //
  263. // On Windows 9x, there is essentially no security, so anyone is able
  264. // to reboot the computer. On Windows NT/2000/XP, things are a bit
  265. // more restrictive. If an application wants to do a reboot at the
  266. // end of a setup, it needs adjust the privileges of the user by
  267. // calling the AdjustTokenPrivileges API.
  268. //
  269. // In this case, we evaluate the flag passed and decide if we should
  270. // adjust the privileges.
  271. //
  272. // Obviously applications should not do this (evaluate some kind of flag)
  273. // as this is just for demonstration purposes.
  274. //
  275. if (!fReboot) {
  276. ExitWindowsEx(EWX_REBOOT, 0);
  277. } else {
  278. ShutdownSystem(FALSE, TRUE);
  279. }
  280. }
  281. /*++
  282. Routine Description:
  283. Attempts to get available disk space.
  284. Arguments:
  285. None.
  286. Return Value:
  287. TRUE if enough disk space is available, FALSE otherwise.
  288. --*/
  289. BOOL
  290. BadGetFreeDiskSpace(
  291. void
  292. )
  293. {
  294. //
  295. // GetDiskFreeSpace returns a maximum total size and maximum free
  296. // size of 2GB. For example, if you have a 6GB volume and 5GB are
  297. // free, GetDiskFreeSpace reports that the drive's total size is 2GB
  298. // and 2GB are free. This limitation originated because the first version
  299. // of Windows 95 only supported volumes of up to 2GB in size. Windows 95
  300. // OSR2 and later versions, including Windows 98, support volumes larger
  301. // than 2GB. GetDiskFreeSpaceEx does not have a 2GB limitation, thus
  302. // it is preferred over GetDiskFreeSpace. GetDiskFreeSpace returns a
  303. // maximum of 65536 for the numbers of total clusters and free clusters
  304. // to maintain backward compatibility with the first version of Windows 95.
  305. // The first version of Windows 95 supports only the FAT16 file system,
  306. // which has a maximum of 65536 clusters. If a FAT32 volume has more than
  307. // 65536 clusters, the number of clusters are reported as 65536 and the
  308. // number of sectors per cluster are adjusted so that the size of volumes
  309. // smaller than 2GB may be calculated correctly. What this means is that
  310. // you should not use GetDiskFreeSpace to return the true geometry
  311. // information for FAT32 volumes.
  312. //
  313. // In case you're wondering, always use the GetDiskFreeSpaceEx API
  314. // on Windows 2000/XP.
  315. //
  316. BOOL fResult = FALSE;
  317. HRESULT hr;
  318. char szWinDir[MAX_PATH];
  319. char* lpDrive = NULL;
  320. DWORD dwSectPerClust = 0,
  321. dwBytesPerSect = 0,
  322. dwFreeClusters = 0,
  323. dwTotalClusters = 0,
  324. dwTotalBytes = 0,
  325. dwFreeBytes = 0,
  326. dwFreeMBs = 0;
  327. //
  328. // Get the drive that windows is installed on and pass it
  329. // to the GetDiskFreeSpace call.
  330. //
  331. hr = StringCchCopy(szWinDir, sizeof(szWinDir), g_ai.szWinDir);
  332. if (FAILED(hr)) {
  333. return FALSE;
  334. }
  335. lpDrive = strstr(szWinDir, "\\");
  336. //
  337. // Make the buffer just 'C:\' (or whatever).
  338. //
  339. if (lpDrive) {
  340. *++lpDrive = '\0';
  341. }
  342. fResult = GetDiskFreeSpace(szWinDir,
  343. &dwSectPerClust,
  344. &dwBytesPerSect,
  345. &dwFreeClusters,
  346. &dwTotalClusters);
  347. if (fResult) {
  348. //
  349. // Normally we would use the __int64 data type,
  350. // but we want the calculations to fail for demonstration.
  351. //
  352. dwTotalBytes = dwTotalClusters * dwSectPerClust * dwBytesPerSect;
  353. dwFreeBytes = dwFreeClusters * dwSectPerClust * dwBytesPerSect;
  354. dwFreeMBs = dwFreeBytes / (1024 * 1024);
  355. if (dwFreeMBs < 100) {
  356. return FALSE;
  357. }
  358. }
  359. return TRUE;
  360. }
  361. /*++
  362. Routine Description:
  363. Displays the readme, if desired.
  364. Arguments:
  365. fDisplay - A flag to indicate if the readme
  366. should be displayed.
  367. Return Value:
  368. None.
  369. --*/
  370. void
  371. BadDisplayReadme(
  372. IN BOOL fDisplay
  373. )
  374. {
  375. // Windows NT/2000/XP contains a new registry data type, REG_EXPAND_SZ,
  376. // that was not found in Win9x. The type contains a variable that needs
  377. // to be expanded before it can be referred to. For example,
  378. // %ProgramFiles% would expand to something like C:\Program Files.
  379. // Most applications are unaware of this data type and therefore
  380. // don't handle it properly.
  381. //
  382. CRegistry creg;
  383. HRESULT hr;
  384. LPSTR lpWordpad = NULL;
  385. char szExpWordpad[MAX_PATH];
  386. char szCmdLineArgs[MAX_PATH];
  387. lpWordpad = creg.GetString(HKEY_LOCAL_MACHINE,
  388. REG_WORDPAD,
  389. NULL); // we want the (Default) value
  390. if (!lpWordpad) {
  391. return;
  392. }
  393. //
  394. // At this point, the path looks something like this:
  395. // "%ProgramFiles%\Windows NT\Accessories\WORDPAD.EXE"
  396. // If the user wants to see the readme (bad functionality
  397. // is disabled), we're going to expand the variable to
  398. // get the true path, then launch wordpad
  399. // If not, we'll try to display the readme using the bogus
  400. // path.
  401. if (fDisplay) {
  402. //
  403. // Expand the environment strings, then build a path to our
  404. // readme file, then launch it.
  405. //
  406. ExpandEnvironmentStrings(lpWordpad, szExpWordpad, MAX_PATH);
  407. hr = StringCchPrintf(szCmdLineArgs,
  408. sizeof(szCmdLineArgs),
  409. "\"%hs\\demoapp.txt\"",
  410. g_ai.szDestDir);
  411. if (FAILED(hr)) {
  412. goto exit;
  413. }
  414. BadCreateProcess(szExpWordpad, szCmdLineArgs, TRUE);
  415. } else {
  416. //
  417. // Do all the work above, but don't expand the data
  418. // We don't check the return of the CreateProcess call,
  419. // so the user simply doesn't get to see the readme,
  420. // and we don't display an error.
  421. // This is consistent with most setup applications.
  422. //
  423. hr = StringCchPrintf(szCmdLineArgs,
  424. sizeof(szCmdLineArgs),
  425. "\"%hs\\demoapp.txt\"",
  426. g_ai.szDestDir);
  427. if (FAILED(hr)) {
  428. goto exit;
  429. }
  430. //
  431. // This will fail. See the BadCreateProcess
  432. // function for details.
  433. //
  434. BadCreateProcess(lpWordpad, szCmdLineArgs, FALSE);
  435. }
  436. exit:
  437. if (lpWordpad) {
  438. creg.Free(lpWordpad);
  439. }
  440. }
  441. /*++
  442. Routine Description:
  443. Displays the help file, if desired.
  444. Arguments:
  445. fDisplay - A flag to indicate if the help file
  446. should be displayed.
  447. Return Value:
  448. None.
  449. --*/
  450. void
  451. BadLaunchHelpFile(
  452. IN BOOL fDisplay
  453. )
  454. {
  455. char szCmdLineArgs[MAX_PATH];
  456. char szExeToLaunch[MAX_PATH];
  457. const char szWinHlp[] = "winhelp.exe";
  458. const char szWinHlp32[] = "winhlp32.exe";
  459. HRESULT hr;
  460. if (fDisplay) {
  461. hr = StringCchPrintf(szExeToLaunch,
  462. sizeof(szExeToLaunch),
  463. "%hs\\%hs",
  464. g_ai.szSysDir,
  465. szWinHlp32);
  466. if (FAILED(hr)) {
  467. return;
  468. }
  469. hr = StringCchPrintf(szCmdLineArgs,
  470. sizeof(szCmdLineArgs),
  471. "%hs\\demoapp.hlp",
  472. g_ai.szCurrentDir);
  473. if (FAILED(hr)) {
  474. return;
  475. }
  476. } else {
  477. hr = StringCchPrintf(szExeToLaunch,
  478. sizeof(szExeToLaunch),
  479. "%hs\\%hs",
  480. g_ai.szWinDir,
  481. szWinHlp);
  482. if (FAILED(hr)) {
  483. return;
  484. }
  485. hr = StringCchPrintf(szCmdLineArgs,
  486. sizeof(szCmdLineArgs),
  487. "%hs\\demoapp.hlp",
  488. g_ai.szCurrentDir);
  489. if (FAILED(hr)) {
  490. return;
  491. }
  492. }
  493. BadCreateProcess(szExeToLaunch, szCmdLineArgs, fDisplay);
  494. }
  495. /*++
  496. Routine Description:
  497. Creates a shortcut on the desktop, if desired.
  498. Arguments:
  499. fCorrectWay - Indicates whether the shortcut should be created.
  500. lpDirFileName - Directory and filename where the shortcut
  501. points to.
  502. lpWorkingDir - Working directory (optional).
  503. lpDisplayName - Display name for the shortcut.
  504. Return Value:
  505. None.
  506. --*/
  507. void
  508. BadCreateShortcut(
  509. IN BOOL fCorrectWay,
  510. IN LPSTR lpDirFileName,
  511. IN LPCSTR lpWorkingDir,
  512. IN LPSTR lpDisplayName
  513. )
  514. {
  515. //
  516. // Hard-coded paths are simply a bad practice. APIs are available that
  517. // return proper locations for common folders. Examples are the
  518. // Program Files, Windows, and Temp directories. SHGetFolderPath,
  519. // GetWindowsDirectory, and GetTempPath would provide the correct path
  520. // in each case. Hard-coded paths should never be used.
  521. //
  522. CShortcut cs;
  523. if (!fCorrectWay) {
  524. //
  525. // A hard-coded path is very bad! We should use SHGetFolderPath
  526. // to get the correct path.
  527. //
  528. const char szDirName[] = "C:\\WINDOWS\\DESKTOP";
  529. cs.CreateShortcut(szDirName,
  530. lpDirFileName,
  531. lpDisplayName,
  532. "-runapp",
  533. (LPCSTR)lpWorkingDir,
  534. SW_SHOWNORMAL);
  535. } else {
  536. //
  537. // Create the shortcut properly.
  538. // Notice that we pass a CSIDL for the "common" desktop
  539. // directory. We want this to be displayed to All Users.
  540. //
  541. cs.CreateShortcut(lpDirFileName,
  542. lpDisplayName,
  543. "-runapp",
  544. lpWorkingDir,
  545. SW_SHOWNORMAL,
  546. CSIDL_COMMON_DESKTOPDIRECTORY);
  547. }
  548. }
  549. #if 0
  550. /*++
  551. Routine Description:
  552. Demonstrates an AV because we used a fixed-size
  553. buffer for a call to GetFileVersionInfo.
  554. Arguments:
  555. fCorrect - A flag to indicate if we should work properly.
  556. Return Value:
  557. None.
  558. --*/
  559. void
  560. BadBufferOverflow(
  561. IN BOOL fCorrect
  562. )
  563. {
  564. //
  565. // Although this problem has only been seen in one application, it's
  566. // worth mentioning here. On Win9x/ME, version resources on DLLs are much
  567. // smaller than ones on NT/2000/XP. Specifically, in the case below,
  568. // the Windows 2000/XP resource size is 6 times larger than the 9x/ME size!
  569. // One particular application used a stack-based buffer (which is fixed in
  570. // size) for the call to GetFileVersionInfo. This worked properly on
  571. // Win9x/ME because the required size was very small. But the required size
  572. // is larger on NT/2000/XP, thus the buffer gets overwritten, causing stack
  573. // corruption. The proper way is to call the GetFileVersionInfoSize API,
  574. // and then allocate a heap-based buffer of an approriate size.
  575. //
  576. //
  577. DWORD cbReqSize = 0;
  578. DWORD dwHandle = 0;
  579. DWORDLONG dwVersion = 0;
  580. UINT nLen = 0;
  581. VS_FIXEDFILEINFO* pffi;
  582. char szDll[MAX_PATH];
  583. HRESULT hr;
  584. PVOID pBadBlock = NULL;
  585. PVOID pVersionBlock = NULL;
  586. HANDLE hHeap = NULL;
  587. SYSTEM_INFO si;
  588. hr = StringCchPrintf(szDll,
  589. sizeof(szDll),
  590. "%hs\\%hs",
  591. g_ai.szSysDir,
  592. szDll);
  593. if (FAILED(hr)) {
  594. return;
  595. }
  596. //
  597. // Get the size of the buffer that will be required for a call to
  598. // GetFileVersionInfo.
  599. //
  600. cbReqSize = GetFileVersionInfoSize(szDll, &dwHandle);
  601. if (!cbReqSize == 0) {
  602. return;
  603. }
  604. if (fCorrect) {
  605. //
  606. // If we're doing this properly, allocate memory from the heap.
  607. //
  608. pVersionBlock = HeapAlloc(GetProcessHeap(),
  609. HEAP_ZERO_MEMORY,
  610. cbReqSize);
  611. if (!pVersionBlock) {
  612. return;
  613. }
  614. //
  615. // Get the version info and query the root block.
  616. //
  617. if (!GetFileVersionInfo(szDll,
  618. dwHandle,
  619. cbReqSize,
  620. pVersionBlock)) {
  621. goto cleanup;
  622. }
  623. if (VerQueryValue(pVersionBlock,
  624. "\\",
  625. (LPVOID*)&pffi,
  626. &nLen))
  627. {
  628. dwVersion = (((DWORDLONG)pffi->dwFileVersionMS) << 32) +
  629. pffi->dwFileVersionLS;
  630. }
  631. } else {
  632. //
  633. // Use a non-growable heap that's way too small.
  634. //
  635. GetSystemInfo(&si);
  636. //
  637. // Create a block and allocate memory from it.
  638. //
  639. hHeap = HeapCreate(0,
  640. si.dwPageSize,
  641. 504); // this was the size needed on Win9x
  642. if (!hHeap) {
  643. return;
  644. }
  645. pBadBlock = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 504);
  646. if (!pBadBlock) {
  647. HeapDestroy(hHeap);
  648. return;
  649. }
  650. //
  651. // Get the version info, passing the buffer (which is too small)
  652. // with a size argument that's incorrect.
  653. //
  654. if (!GetFileVersionInfo(szDll,
  655. dwHandle,
  656. 3072, // this is the size needed on Win2K/XP
  657. pBadBlock))
  658. {
  659. goto cleanup;
  660. }
  661. if (VerQueryValue(pBadBlock,
  662. "\\",
  663. (LPVOID*)&pffi,
  664. &nLen))
  665. {
  666. dwVersion = (((DWORDLONG)pffi->dwFileVersionMS) << 32) +
  667. pffi->dwFileVersionLS;
  668. }
  669. }
  670. cleanup:
  671. if (pBadBlock) {
  672. HeapFree(hHeap, 0, pBadBlock);
  673. }
  674. if (pVersionBlock) {
  675. HeapFree(GetProcessHeap(), 0, pVersionBlock);
  676. }
  677. if (hHeap) {
  678. HeapDestroy(hHeap);
  679. }
  680. }
  681. #endif
  682. /*++
  683. Routine Description:
  684. Demonstrates an AV because we used a non-growable heap
  685. during file operations.
  686. Arguments:
  687. None.
  688. Return Value:
  689. None.
  690. --*/
  691. void
  692. BadCorruptHeap(
  693. void
  694. )
  695. {
  696. SYSTEM_INFO SystemInfo;
  697. HANDLE hHeap;
  698. HRESULT hr;
  699. char* pszBigBlock = NULL;
  700. char* pszBigBlock1 = NULL;
  701. char* pszTestInputFile = NULL;
  702. char* pszTestOutputFile = NULL;
  703. FILE* hFile = NULL;
  704. FILE* hFileOut = NULL;
  705. DWORD dwCount = 0;
  706. int nCount = 0;
  707. const char szAlpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
  708. const char szMsg[] = "This is a corrupted heap -- Heap Overflow! Bad Programming!";
  709. //
  710. // Get system page size.
  711. //
  712. GetSystemInfo(&SystemInfo);
  713. //
  714. // Create a local, non-growable heap.
  715. //
  716. hHeap = HeapCreate(0, SystemInfo.dwPageSize, 0x7FFF8);
  717. if (!hHeap) {
  718. return;
  719. }
  720. //
  721. // Allocate memory from the local heap.
  722. //
  723. pszBigBlock = (char*)HeapAlloc(hHeap, 0, 0x6FFF8);
  724. pszBigBlock1 = (char*)HeapAlloc(hHeap, 0, 0xFFF);
  725. pszTestInputFile = (char*)HeapAlloc(hHeap, 0, MAX_PATH);
  726. pszTestOutputFile = (char*)HeapAlloc(hHeap, 0, MAX_PATH);
  727. if (!pszBigBlock || !pszBigBlock1 || !pszTestInputFile || !pszTestOutputFile) {
  728. HeapDestroy(hHeap);
  729. return;
  730. }
  731. hr = StringCchCopy(pszBigBlock1, 0xFFF, szMsg);
  732. if (FAILED(hr)) {
  733. goto exit;
  734. }
  735. GetCurrentDirectory(MAX_PATH, pszTestInputFile);
  736. //
  737. // Set up the file names.
  738. //
  739. hr = StringCchCopy(pszTestOutputFile, MAX_PATH, pszTestInputFile);
  740. if (FAILED(hr)) {
  741. goto exit;
  742. }
  743. hr = StringCchCat(pszTestInputFile, MAX_PATH, "\\test.txt");
  744. if (FAILED(hr)) {
  745. goto exit;
  746. }
  747. hr = StringCchCat(pszTestOutputFile, MAX_PATH, "\\test_out.txt");
  748. if (FAILED(hr)) {
  749. goto exit;
  750. }
  751. //
  752. // Open the file for writing.
  753. //
  754. hFileOut = fopen(pszTestInputFile, "wt");
  755. if (!hFileOut) {
  756. goto exit;
  757. }
  758. //
  759. // Put some junk data in the file - about 1.5 MBs worth.
  760. //
  761. for (dwCount = 0; dwCount < 0xABCD; dwCount++) {
  762. fwrite(szAlpha, sizeof(char), 36, hFileOut);
  763. }
  764. fclose(hFileOut);
  765. //
  766. // Open the files for reading & writing.
  767. //
  768. hFileOut = fopen(pszTestInputFile, "r");
  769. if (!hFileOut) {
  770. goto exit;
  771. }
  772. hFile = fopen(pszTestOutputFile, "w");
  773. if (!hFile) {
  774. goto exit;
  775. }
  776. //
  777. // Read some data from the large file.
  778. //
  779. nCount = fread(pszBigBlock, sizeof(char), 0x6FFFF, hFileOut);
  780. if (!nCount) {
  781. goto exit;
  782. }
  783. //
  784. // Write some test data to a separate file.
  785. //
  786. nCount = fwrite(pszBigBlock, sizeof(char), nCount, hFile);
  787. exit:
  788. if (hFile) {
  789. fclose(hFile);
  790. }
  791. if (hFileOut) {
  792. fclose(hFileOut);
  793. }
  794. HeapFree(hHeap, 0, pszBigBlock);
  795. HeapFree(hHeap, 0, pszBigBlock1);
  796. HeapFree(hHeap, 0, pszTestInputFile);
  797. HeapFree(hHeap, 0, pszTestOutputFile);
  798. HeapDestroy(hHeap);
  799. }
  800. /*++
  801. Routine Description:
  802. Loads a library, frees it, then tries to call an exported
  803. function. This will cause an access violation.
  804. Arguments:
  805. None.
  806. Return Value:
  807. None.
  808. --*/
  809. void
  810. BadLoadLibrary(
  811. void
  812. )
  813. {
  814. char szDll[MAX_PATH];
  815. const char szDemoDll[] = "demodll.dll";
  816. HINSTANCE hInstance;
  817. HRESULT hr;
  818. hr = StringCchPrintf(szDll,
  819. sizeof(szDll),
  820. "%hs\\%hs",
  821. g_ai.szCurrentDir,
  822. szDemoDll);
  823. if (FAILED(hr)) {
  824. return;
  825. }
  826. hInstance = LoadLibrary(szDll);
  827. if (!hInstance) {
  828. return;
  829. }
  830. //
  831. // Get the address of the function.
  832. //
  833. DemoAppExpFunc = (LPFNDEMOAPPEXP)GetProcAddress(hInstance, "DemoAppExp");
  834. FreeLibrary(hInstance);
  835. }
  836. /*++
  837. Routine Description:
  838. Uses the WriteFile API and passes NULL for lpBuffer.
  839. This is legal on Win9x, not on NT/2000/XP.
  840. Arguments:
  841. None.
  842. Return Value:
  843. TRUE on success, FALSE otherwise.
  844. --*/
  845. BOOL
  846. BadWriteToFile(
  847. void
  848. )
  849. {
  850. //
  851. // On Win9x/ME, applications could call the WriteFile API and pass
  852. // a NULL for the lpBuffer argument. This would be interpreted as
  853. // zeros. On NT/2000, this is not the case and this call will fail.
  854. //
  855. char szTempFile[MAX_PATH];
  856. char szTempPath[MAX_PATH];
  857. UINT uReturn;
  858. HANDLE hFile;
  859. BOOL fReturn = FALSE;
  860. DWORD cbBytesWritten;
  861. DWORD cchSize;
  862. cchSize = GetTempPath(sizeof(szTempPath), szTempPath);
  863. if (cchSize > sizeof(szTempPath) || cchSize == 0) {
  864. return FALSE;
  865. }
  866. //
  867. // Build a path to a temp file.
  868. //
  869. uReturn = GetTempFileName(szTempPath, "_dem", 0, szTempFile);
  870. if (!uReturn) {
  871. return FALSE;
  872. }
  873. //
  874. // Get a handle to the newly created file.
  875. //
  876. hFile = CreateFile(szTempFile,
  877. GENERIC_WRITE,
  878. FILE_SHARE_WRITE | FILE_SHARE_READ,
  879. NULL,
  880. OPEN_ALWAYS,
  881. FILE_ATTRIBUTE_NORMAL,
  882. NULL);
  883. if (INVALID_HANDLE_VALUE == hFile) {
  884. return FALSE;
  885. }
  886. //
  887. // Try to write some data to the file, but pass a NULL buffer.
  888. //
  889. fReturn = WriteFile(hFile, NULL, 10, &cbBytesWritten, NULL);
  890. CloseHandle(hFile);
  891. return fReturn;
  892. }
  893. /*++
  894. Routine Description:
  895. Wrapper function for CreateProcess. Doesn't initialize the
  896. STARTUPINFO structure properly, causing the process not to
  897. be launched.
  898. Arguments:
  899. lpApplicationName - Application name to launch.
  900. lpCommandLine - Command line arguments to pass to the EXE.
  901. fLaunch - A flag to indicate if we should work properly.
  902. Return Value:
  903. TRUE on success, FALSE otherwise.
  904. --*/
  905. BOOL
  906. BadCreateProcess(
  907. IN LPSTR lpApplicationName,
  908. IN LPSTR lpCommandLine,
  909. IN BOOL fLaunch
  910. )
  911. {
  912. //
  913. // On Win9x/ME, the CreateProcess API isn't overly concerned with the
  914. // members of the STARTUPINFO structure. On NT/2000/XP, more parameter
  915. // validation is done, and if the parameters are bad or incorrect, the
  916. // call fails. This causes an application error message to appear.
  917. //
  918. BOOL fReturn = FALSE;
  919. STARTUPINFO si;
  920. PROCESS_INFORMATION pi;
  921. if (!lpApplicationName) {
  922. return FALSE;
  923. }
  924. ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  925. ZeroMemory(&si, sizeof(STARTUPINFO));
  926. si.cb = sizeof(STARTUPINFO);
  927. if (fLaunch) {
  928. fReturn = CreateProcess(lpApplicationName,
  929. lpCommandLine,
  930. NULL,
  931. NULL,
  932. FALSE,
  933. 0,
  934. NULL,
  935. NULL,
  936. &si,
  937. &pi);
  938. } else {
  939. //
  940. // Provide bad values for structure members.
  941. //
  942. si.lpReserved = "Never store data in reserved areas...";
  943. si.cbReserved2 = 1;
  944. si.lpReserved2 = (LPBYTE)"Microsoft has these reserved for a reason...";
  945. si.lpDesktop = "Bogus desktop!!!!";
  946. fReturn = CreateProcess(lpApplicationName,
  947. lpCommandLine,
  948. NULL,
  949. NULL,
  950. FALSE,
  951. 0,
  952. NULL,
  953. NULL,
  954. &si,
  955. &pi);
  956. }
  957. if (pi.hThread) {
  958. CloseHandle(pi.hThread);
  959. }
  960. if (pi.hProcess) {
  961. CloseHandle(pi.hProcess);
  962. }
  963. return fReturn;
  964. }
  965. /*++
  966. Routine Description:
  967. Attempts to save/retrieve our position information to
  968. the registry. We perform this operation in HKLM, not
  969. HKCU. This demonstrates what happens when an application
  970. attempts to save information to the registry when the user
  971. does not have permissions to do so because they're not an
  972. administrator.
  973. Arguments:
  974. fSave - If true, indicates we're saving data.
  975. *lppt - A POINT structure that contains/receives our data.
  976. Return Value:
  977. TRUE on success, FALSE otherwise.
  978. --*/
  979. BOOL
  980. BadSaveToRegistry(
  981. IN BOOL fSave,
  982. IN OUT POINT* lppt
  983. )
  984. {
  985. BOOL bReturn = FALSE;
  986. HKEY hKey;
  987. HKEY hKeyRoot;
  988. DWORD cbSize = 0, dwDisposition = 0;
  989. LONG lRetVal;
  990. char szKeyName[] = "DlgCoordinates";
  991. //
  992. // Initialize our coordinates in case there's no data there.
  993. //
  994. if (!fSave) {
  995. lppt->x = lppt->y = 0;
  996. }
  997. if (g_ai.fEnableBadFunc) {
  998. hKeyRoot = HKEY_LOCAL_MACHINE;
  999. } else {
  1000. hKeyRoot = HKEY_CURRENT_USER;
  1001. }
  1002. //
  1003. // Open the registry key (or create it if the first time being used).
  1004. //
  1005. lRetVal = RegCreateKeyEx(hKeyRoot,
  1006. REG_APP_KEY,
  1007. 0,
  1008. 0,
  1009. REG_OPTION_NON_VOLATILE,
  1010. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1011. 0,
  1012. &hKey,
  1013. &dwDisposition);
  1014. if (ERROR_SUCCESS != lRetVal) {
  1015. return FALSE;
  1016. }
  1017. //
  1018. // Save or retrieve our coordinates.
  1019. //
  1020. if (fSave) {
  1021. lRetVal = RegSetValueEx(hKey,
  1022. szKeyName,
  1023. 0,
  1024. REG_BINARY,
  1025. (const BYTE*)lppt,
  1026. sizeof(*lppt));
  1027. if (ERROR_SUCCESS != lRetVal) {
  1028. goto exit;
  1029. }
  1030. } else {
  1031. cbSize = sizeof(*lppt);
  1032. lRetVal = RegQueryValueEx(hKey,
  1033. szKeyName,
  1034. 0,
  1035. 0,
  1036. (LPBYTE)lppt,
  1037. &cbSize);
  1038. if (ERROR_SUCCESS != lRetVal) {
  1039. goto exit;
  1040. }
  1041. }
  1042. bReturn = TRUE;
  1043. exit:
  1044. RegCloseKey(hKey);
  1045. return bReturn;
  1046. }
  1047. /*++
  1048. Routine Description:
  1049. Attempts to create a temp file (that won't be used)
  1050. in the Windows directory. We do this to demonstrate
  1051. what happens when an application attempts to write
  1052. to a directory that the user does not have access to
  1053. because they are not an administrator.
  1054. Arguments:
  1055. None.
  1056. Return Value:
  1057. TRUE on success, FALSE otherwise.
  1058. --*/
  1059. BOOL
  1060. BadCreateTempFile(
  1061. void
  1062. )
  1063. {
  1064. char szTempFile[MAX_PATH];
  1065. HANDLE hFile;
  1066. HRESULT hr;
  1067. //
  1068. // We return TRUE if these functions fail because returning
  1069. // FALSE causes an error to be displayed, and Compatiblity
  1070. // Fixes will not correct the error.
  1071. //
  1072. hr = StringCchPrintf(szTempFile,
  1073. sizeof(szTempFile),
  1074. "%hs\\demotemp.tmp",
  1075. g_ai.szWinDir);
  1076. if (FAILED(hr)) {
  1077. return TRUE;
  1078. }
  1079. hFile = CreateFile(szTempFile,
  1080. GENERIC_ALL,
  1081. 0,
  1082. NULL,
  1083. CREATE_ALWAYS,
  1084. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
  1085. NULL);
  1086. if (INVALID_HANDLE_VALUE == hFile) {
  1087. return FALSE;
  1088. }
  1089. CloseHandle(hFile);
  1090. return TRUE;
  1091. }