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.

522 lines
16 KiB

  1. /*
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. RegQueryValueEx.cpp
  5. Abstract:
  6. This DLL hooks RegQueryValueExA so that we can return the "all-users" location
  7. for the StartMenu, Desktop and Startup folders instead of the per-user location.
  8. We also hook RegCreateKeyA/RegCreateKeyExA to make people who add entries to the
  9. HKCU "run" and "Uninstall" keys really add them to HKLM.
  10. Notes:
  11. History:
  12. 08/07/2000 reinerf Created
  13. 02/27/2001 robkenny Converted to use CString
  14. */
  15. #include "precomp.h"
  16. // This module has been given an official blessing to use the str routines.
  17. #include "LegalStr.h"
  18. IMPLEMENT_SHIM_BEGIN(ProfilesRegQueryValueEx)
  19. #include "ShimHookMacro.h"
  20. #include <shlwapi.h> // for StrRStrIA
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_ENTRY(RegQueryValueExA)
  23. APIHOOK_ENUM_ENTRY(RegCreateKeyA)
  24. APIHOOK_ENUM_ENTRY(RegCreateKeyExA)
  25. APIHOOK_ENUM_ENTRY(RegOpenKeyA)
  26. APIHOOK_ENUM_ENTRY(RegOpenKeyExA)
  27. APIHOOK_ENUM_END
  28. #ifndef MAX
  29. #define MAX(x,y) (((x) > (y)) ? (x) : (y))
  30. #endif
  31. #ifndef ARRAYSIZE
  32. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  33. #endif
  34. LPCSTR g_aBadKeys[] =
  35. {
  36. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"},
  37. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"},
  38. };
  39. LPCSTR g_aBadShellFolderKeys[] =
  40. {
  41. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"},
  42. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"},
  43. };
  44. // given an hkey, call NtQueryObject to lookup its name.
  45. // returns strings in the format: "\REGISTRY\USER\S-1-5-xxxxx\Software\Microsoft\Windows\CurrentVersion"
  46. BOOL GetKeyName(HKEY hk, LPSTR pszName, DWORD cchName)
  47. {
  48. BOOL bRet = FALSE;
  49. ULONG cbSize = 0;
  50. // get the size needed for the name buffer
  51. NtQueryObject(hk, ObjectNameInformation, NULL, 0, &cbSize);
  52. if (cbSize)
  53. {
  54. POBJECT_NAME_INFORMATION pNameInfo = (POBJECT_NAME_INFORMATION)LocalAlloc(LPTR, cbSize);
  55. if (pNameInfo)
  56. {
  57. NTSTATUS status = NtQueryObject(hk, ObjectNameInformation, (void*)pNameInfo, cbSize, NULL);
  58. if (NT_SUCCESS(status) && WideCharToMultiByte(CP_ACP, 0, pNameInfo->Name.Buffer, -1, pszName, cchName, NULL, NULL))
  59. {
  60. bRet = TRUE;
  61. }
  62. LocalFree(pNameInfo);
  63. }
  64. }
  65. return bRet;
  66. }
  67. // If hk points underneath HKCU and matches pszSearchName, then return TRUE
  68. BOOL DoesKeyMatch(HKEY hk, LPCSTR pszSearchName)
  69. {
  70. BOOL bRet = FALSE;
  71. // make sure it is not one of the pre-defined keys (eg HKEY_LOCAL_MACHINE)
  72. if (!((LONG)((ULONG_PTR)hk) & 0x80000000))
  73. {
  74. CHAR szKeyName[MAX_PATH * 2]; // should be big enought to hold any registry key path
  75. if (GetKeyName(hk, szKeyName, ARRAYSIZE(szKeyName)))
  76. {
  77. // is the key under HKCU ?
  78. if (StrCmpNIA(szKeyName, "\\REGISTRY\\USER\\", ARRAYSIZE("\\REGISTRY\\USER\\")-1) == 0)
  79. {
  80. LPSTR psz = StrRStrIA(szKeyName, NULL, pszSearchName);
  81. if (psz && (lstrlenA(psz) == lstrlenA(pszSearchName)))
  82. {
  83. // we found a substring and its the same length, so our hkey matches the search!
  84. bRet = TRUE;
  85. }
  86. }
  87. }
  88. }
  89. return bRet;
  90. }
  91. BOOL IsBadHKCUKey(HKEY hk, LPCSTR* ppszNewKey)
  92. {
  93. BOOL bRet = FALSE;
  94. int i;
  95. for (i=0; i < ARRAYSIZE(g_aBadKeys); i++)
  96. {
  97. if (DoesKeyMatch(hk, g_aBadKeys[i]))
  98. {
  99. *ppszNewKey = g_aBadKeys[i];
  100. bRet = TRUE;
  101. break;
  102. }
  103. }
  104. return bRet;
  105. }
  106. BOOL IsBadShellFolderKey(HKEY hk, LPCSTR* ppszNewKey)
  107. {
  108. BOOL bRet = FALSE;
  109. int i;
  110. for (i=0; i < ARRAYSIZE(g_aBadShellFolderKeys); i++)
  111. {
  112. if (DoesKeyMatch(hk, g_aBadShellFolderKeys[i]))
  113. {
  114. *ppszNewKey = g_aBadShellFolderKeys[i];
  115. bRet = TRUE;
  116. break;
  117. }
  118. }
  119. return bRet;
  120. }
  121. LONG
  122. APIHOOK(RegCreateKeyA)(
  123. HKEY hKey,
  124. LPCSTR pszSubKey,
  125. PHKEY phkResult
  126. )
  127. {
  128. LPCSTR pszNewHKLMKey;
  129. LONG lRet = ORIGINAL_API(RegCreateKeyA)(hKey, pszSubKey, phkResult);
  130. if ((lRet == ERROR_SUCCESS) &&
  131. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  132. {
  133. // its a bad HKCU key-- redirect to HKLM
  134. RegCloseKey(*phkResult);
  135. lRet = ORIGINAL_API(RegCreateKeyA)(HKEY_LOCAL_MACHINE, pszNewHKLMKey, phkResult);
  136. LOGN(eDbgLevelInfo, "[RegCreateKeyA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  137. }
  138. return lRet;
  139. }
  140. LONG
  141. APIHOOK(RegCreateKeyExA)(
  142. HKEY hKey,
  143. LPCSTR pszSubKey,
  144. DWORD Reserved,
  145. LPSTR lpClass,
  146. DWORD dwOptions,
  147. REGSAM samDesired,
  148. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  149. PHKEY phkResult,
  150. LPDWORD lpdwDisposition
  151. )
  152. {
  153. LPCSTR pszNewHKLMKey;
  154. LONG lRet = ORIGINAL_API(RegCreateKeyExA)(hKey,
  155. pszSubKey,
  156. Reserved,
  157. lpClass,
  158. dwOptions,
  159. samDesired,
  160. lpSecurityAttributes,
  161. phkResult,
  162. lpdwDisposition);
  163. if ((lRet == ERROR_SUCCESS) &&
  164. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  165. {
  166. // its a bad HCKU key-- redirect to HKLM
  167. RegCloseKey(*phkResult);
  168. lRet = ORIGINAL_API(RegCreateKeyExA)(HKEY_LOCAL_MACHINE,
  169. pszNewHKLMKey,
  170. Reserved,
  171. lpClass,
  172. dwOptions,
  173. samDesired,
  174. lpSecurityAttributes,
  175. phkResult,
  176. lpdwDisposition);
  177. LOGN(eDbgLevelInfo, "[RegCreateKeyExA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  178. }
  179. return lRet;
  180. }
  181. LONG
  182. APIHOOK(RegOpenKeyA)(
  183. HKEY hKey,
  184. LPCSTR pszSubKey,
  185. PHKEY phkResult
  186. )
  187. {
  188. LPCSTR pszNewHKLMKey;
  189. LONG lRet = ORIGINAL_API(RegOpenKeyA)(hKey, pszSubKey, phkResult);
  190. if ((lRet == ERROR_SUCCESS) &&
  191. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  192. {
  193. // its a bad HCKU key-- redirect to HKLM
  194. RegCloseKey(*phkResult);
  195. lRet = ORIGINAL_API(RegOpenKeyA)(HKEY_LOCAL_MACHINE, pszNewHKLMKey, phkResult);
  196. LOGN(eDbgLevelInfo, "[RegOpenKeyA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  197. }
  198. return lRet;
  199. }
  200. LONG
  201. APIHOOK(RegOpenKeyExA)(
  202. HKEY hKey,
  203. LPCSTR pszSubKey,
  204. DWORD ulOptions,
  205. REGSAM samDesired,
  206. PHKEY phkResult
  207. )
  208. {
  209. LPCSTR pszNewHKLMKey;
  210. LONG lRet = ORIGINAL_API(RegOpenKeyExA)(hKey, pszSubKey, ulOptions, samDesired, phkResult);
  211. if ((lRet == ERROR_SUCCESS) &&
  212. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  213. {
  214. // its a bad HCKU key-- redirect to HKLM
  215. RegCloseKey(*phkResult);
  216. lRet = ORIGINAL_API(RegOpenKeyExA)(HKEY_LOCAL_MACHINE, pszNewHKLMKey, ulOptions, samDesired, phkResult);
  217. LOGN(eDbgLevelInfo, "[RegOpenKeyExA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  218. }
  219. return lRet;
  220. }
  221. LONG
  222. GetAllUsersRegValueA(
  223. LPSTR szRegValue,
  224. DWORD cbOriginal,
  225. DWORD* pcbData,
  226. int nFolder,
  227. int nFolderCommon
  228. )
  229. {
  230. LONG lRet = ERROR_SUCCESS;
  231. if (!szRegValue)
  232. {
  233. // if the caller is querying for the necessary size, return the "worst case" since we don't know if
  234. // we are going to have to lie or not
  235. *pcbData = MAX_PATH;
  236. }
  237. else if (szRegValue[0] != '\0')
  238. {
  239. CHAR szPath[MAX_PATH];
  240. if (SUCCEEDED(SHGetFolderPathA(NULL, nFolder, NULL, SHGFP_TYPE_CURRENT, szPath))) {
  241. CHAR szShortRegPath[MAX_PATH];
  242. CHAR szShortGSFPath[MAX_PATH];
  243. BOOL bUseLFN;
  244. BOOL bSame = FALSE;
  245. if (lstrcmpiA(szPath, szRegValue) == 0) {
  246. bSame = TRUE;
  247. bUseLFN = TRUE;
  248. } else if (GetShortPathNameA(szPath, szShortGSFPath, ARRAYSIZE(szShortGSFPath)) &&
  249. GetShortPathNameA(szRegValue, szShortRegPath, ARRAYSIZE(szShortRegPath)) &&
  250. (lstrcmpiA(szShortGSFPath, szShortRegPath) == 0)) {
  251. bSame = TRUE;
  252. //
  253. // Since the sfn was returned, use that to copy over the output buffer.
  254. //
  255. bUseLFN = FALSE;
  256. }
  257. if (bSame && SUCCEEDED(SHGetFolderPathA(NULL, nFolderCommon, NULL, SHGFP_TYPE_CURRENT, szPath))) {
  258. if (bUseLFN) {
  259. if ((lstrlenA(szPath) + 1) <= (int)cbOriginal) {
  260. LOGN(
  261. eDbgLevelInfo,
  262. "[GetAllUsersRegValueA] overriding per-user reg value w/ common value");
  263. lstrcpyA(szRegValue, szPath);
  264. } else {
  265. LOGN(
  266. eDbgLevelInfo,
  267. "[GetAllUsersRegValueA] returning ERROR_MORE_DATA for special folder value");
  268. lRet = ERROR_MORE_DATA;
  269. }
  270. //
  271. // Either we used this much room, or this is how much we need to have.
  272. //
  273. *pcbData = lstrlenA(szPath) + 1;
  274. } else if (GetShortPathNameA(szPath, szShortGSFPath, ARRAYSIZE(szShortGSFPath))) {
  275. if ((lstrlenA(szShortGSFPath) + 1) <= (int)cbOriginal) {
  276. LOGN(
  277. eDbgLevelInfo,
  278. "[GetAllUsersRegValueA] overriding per-user reg value w/ common value");
  279. lstrcpyA(szRegValue, szShortGSFPath);
  280. } else {
  281. LOGN(
  282. eDbgLevelInfo,
  283. "[GetAllUsersRegValueA] returning ERROR_MORE_DATA for special folder value");
  284. lRet = ERROR_MORE_DATA;
  285. }
  286. //
  287. // Either we used this much room, or this is how much we need to have.
  288. //
  289. *pcbData = lstrlenA(szShortGSFPath) + 1;
  290. }
  291. }
  292. }
  293. }
  294. return lRet;
  295. }
  296. //
  297. // If the app is asking for the per-user "Desktop", "Start Menu" or "Startup" values by
  298. // groveling the registry, then redirect it to the proper per-machine values.
  299. //
  300. LONG
  301. APIHOOK(RegQueryValueExA)(
  302. HKEY hKey, // handle to key
  303. LPCSTR lpValueName, // value name
  304. LPDWORD lpReserved, // reserved
  305. LPDWORD lpType, // type buffer
  306. LPBYTE lpData, // data buffer
  307. LPDWORD lpcbData // size of data buffer
  308. )
  309. {
  310. DWORD cbOriginal = (lpcbData ? *lpcbData : 0); // save off the original buffer size
  311. LPCSTR pszNewHKLMKey;
  312. LONG lRet = ORIGINAL_API(RegQueryValueExA)(hKey,
  313. lpValueName,
  314. lpReserved,
  315. lpType,
  316. lpData,
  317. lpcbData);
  318. if ((lpValueName && lpcbData) && // (not simply checking for existance of the value...)
  319. IsBadShellFolderKey(hKey, &pszNewHKLMKey))
  320. {
  321. CHAR szTemp[MAX_PATH];
  322. if (lstrcmpiA(lpValueName, "Desktop") == 0) {
  323. DPFN(
  324. eDbgLevelInfo,
  325. "[RegQueryValueExA] querying for 'Desktop' value\n");
  326. if (lRet == ERROR_SUCCESS) {
  327. lRet = GetAllUsersRegValueA((LPSTR)lpData,
  328. cbOriginal,
  329. lpcbData,
  330. CSIDL_DESKTOP,
  331. CSIDL_COMMON_DESKTOPDIRECTORY);
  332. } else if (lRet == ERROR_MORE_DATA) {
  333. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  334. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  335. }
  336. }
  337. } else if (lstrcmpiA(lpValueName, "Start Menu") == 0) {
  338. DPFN(
  339. eDbgLevelInfo,
  340. "[RegQueryValueExA] querying for 'Start Menu' value\n");
  341. if (lRet == ERROR_SUCCESS) {
  342. lRet = GetAllUsersRegValueA((LPSTR)lpData,
  343. cbOriginal,
  344. lpcbData,
  345. CSIDL_STARTMENU,
  346. CSIDL_COMMON_STARTMENU);
  347. } else if (lRet == ERROR_MORE_DATA) {
  348. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_STARTMENU, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  349. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  350. }
  351. }
  352. } else if (lstrcmpiA(lpValueName, "Startup") == 0) {
  353. DPFN(
  354. eDbgLevelInfo,
  355. "[RegQueryValueExA] querying for 'Startup' value\n");
  356. if (lRet == ERROR_SUCCESS) {
  357. lRet = GetAllUsersRegValueA((LPSTR)lpData, cbOriginal, lpcbData, CSIDL_STARTUP, CSIDL_COMMON_STARTUP);
  358. } else if (lRet == ERROR_MORE_DATA) {
  359. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_STARTUP, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  360. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  361. }
  362. }
  363. } else if (lstrcmpiA(lpValueName, "Programs") == 0) {
  364. DPFN(
  365. eDbgLevelInfo,
  366. "[RegQueryValueExA] querying for 'Programs' value\n");
  367. if (lRet == ERROR_SUCCESS) {
  368. lRet = GetAllUsersRegValueA((LPSTR)lpData, cbOriginal, lpcbData, CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS);
  369. } else if (lRet == ERROR_MORE_DATA) {
  370. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  371. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  372. }
  373. }
  374. }
  375. }
  376. return lRet;
  377. }
  378. BOOL
  379. NOTIFY_FUNCTION(
  380. DWORD fdwReason
  381. )
  382. {
  383. if (fdwReason == DLL_PROCESS_ATTACH) {
  384. OSVERSIONINFOEX osvi = {0};
  385. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  386. if (GetVersionEx((OSVERSIONINFO*)&osvi)) {
  387. if (!((VER_SUITE_TERMINAL & osvi.wSuiteMask) &&
  388. !(VER_SUITE_SINGLEUSERTS & osvi.wSuiteMask))) {
  389. //
  390. // Only install hooks if we are not on a "Terminal Server"
  391. // (aka "Application Server") machine.
  392. //
  393. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExA);
  394. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyA);
  395. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExA);
  396. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA);
  397. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA);
  398. }
  399. }
  400. }
  401. return TRUE;
  402. }
  403. HOOK_BEGIN
  404. CALL_NOTIFY_FUNCTION
  405. HOOK_END
  406. IMPLEMENT_SHIM_END