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.

3108 lines
74 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. LogRegistryChanges.cpp
  5. Abstract:
  6. This AppVerifier shim hooks all the registry APIs
  7. that change the state of the system and logs their
  8. associated data to a text file.
  9. Notes:
  10. This is a general purpose shim.
  11. History:
  12. 08/17/2001 rparsons Created
  13. 09/20/2001 rparsons File I/O operations use NT APIs
  14. 09/23/2001 rparsons VLOG with log file location
  15. 10/06/2001 rparsons Open key handles are never removed from the list
  16. --*/
  17. #include "precomp.h"
  18. #include "rtlutils.h"
  19. IMPLEMENT_SHIM_BEGIN(LogRegistryChanges)
  20. #include "ShimHookMacro.h"
  21. #include "ShimCString.h"
  22. #include "LogRegistryChanges.h"
  23. BEGIN_DEFINE_VERIFIER_LOG(LogRegistryChanges)
  24. VERIFIER_LOG_ENTRY(VLOG_LOGREGCHANGES_LOGLOC)
  25. END_DEFINE_VERIFIER_LOG(LogRegistryChanges)
  26. INIT_VERIFIER_LOG(LogRegistryChanges);
  27. //
  28. // Stores the NT path to the file system log file for the current session.
  29. //
  30. UNICODE_STRING g_strLogFilePath;
  31. //
  32. // Stores the DOS path to the file system log file for the current session.
  33. // This doesn't get freed.
  34. //
  35. LPWSTR g_pwszLogFilePath;
  36. //
  37. // Head of our open key handle linked list.
  38. //
  39. LIST_ENTRY g_OpenKeyListHead;
  40. //
  41. // Temporary buffer stored on the heap.
  42. // Used when creating XML elements to log.
  43. // This doesn't get freed.
  44. //
  45. LPWSTR g_pwszTempBuffer;
  46. //
  47. // Size of the temporary buffer above.
  48. //
  49. DWORD g_cbTempBufferSize;
  50. //
  51. // Stores the unique id used for NULL value names.
  52. //
  53. WCHAR g_wszUniqueId[MAX_PATH * 2];
  54. //
  55. // Temporary buffers stored on the heap.
  56. // Used when extracting old & new data for logging.
  57. // These don't get freed.
  58. //
  59. LPWSTR g_pwszOriginalData;
  60. LPWSTR g_pwszFinalData;
  61. //
  62. // Size of the temporary buffers above.
  63. //
  64. DWORD g_cbOriginalDataBufferSize;
  65. DWORD g_cbFinalDataBufferSize;
  66. /*++
  67. Writes an entry to the log file.
  68. --*/
  69. void
  70. WriteEntryToLog(
  71. IN LPCWSTR pwszEntry
  72. )
  73. {
  74. int nLen = 0;
  75. HANDLE hFile;
  76. OBJECT_ATTRIBUTES ObjectAttributes;
  77. IO_STATUS_BLOCK IoStatusBlock;
  78. LARGE_INTEGER liOffset;
  79. NTSTATUS status;
  80. //
  81. // Note that we have to use native APIs throughout this function
  82. // to avoid a problem with circular hooking. That is, if we simply
  83. // call WriteFile, which is exported from kernel32, it will call NtWriteFile,
  84. // which is a call that we hook, in turn leaving us in and endless loop.
  85. //
  86. //
  87. // Attempt to get a handle to our log file.
  88. //
  89. InitializeObjectAttributes(&ObjectAttributes,
  90. &g_strLogFilePath,
  91. OBJ_CASE_INSENSITIVE,
  92. NULL,
  93. NULL);
  94. status = NtCreateFile(&hFile,
  95. FILE_APPEND_DATA | SYNCHRONIZE,
  96. &ObjectAttributes,
  97. &IoStatusBlock,
  98. 0,
  99. FILE_ATTRIBUTE_NORMAL,
  100. 0,
  101. FILE_OPEN,
  102. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  103. NULL,
  104. 0);
  105. if (!NT_SUCCESS(status)) {
  106. DPFN(eDbgLevelError, "[WriteEntryToLog] Failed to open log");
  107. return;
  108. }
  109. //
  110. // Write the data out to the file.
  111. //
  112. nLen = wcslen(pwszEntry);
  113. IoStatusBlock.Status = 0;
  114. IoStatusBlock.Information = 0;
  115. liOffset.LowPart = 0;
  116. liOffset.HighPart = 0;
  117. status = NtWriteFile(hFile,
  118. NULL,
  119. NULL,
  120. NULL,
  121. &IoStatusBlock,
  122. (PVOID)pwszEntry,
  123. (ULONG)(nLen) * sizeof(WCHAR),
  124. &liOffset,
  125. NULL);
  126. if (!NT_SUCCESS(status)) {
  127. DPFN(eDbgLevelError, "[WriteEntryToLog] 0x%X Failed to make entry", status);
  128. goto exit;
  129. }
  130. exit:
  131. NtClose(hFile);
  132. }
  133. /*++
  134. Creates our log files using the local time.
  135. It goes into %windir%\AppPatch\VLog.
  136. --*/
  137. BOOL
  138. InitializeLogFile(
  139. void
  140. )
  141. {
  142. BOOL fReturn = FALSE;
  143. HANDLE hFile;
  144. SYSTEMTIME st;
  145. UINT nLen = 0;
  146. WCHAR wszFileLog[64];
  147. WCHAR* pwszLogFile = NULL;
  148. WCHAR* pSlash = NULL;
  149. WCHAR* pDot = NULL;
  150. WCHAR wszModPathName[MAX_PATH];
  151. WCHAR wszShortName[MAX_PATH];
  152. WCHAR wszLogHdr[512];
  153. const WCHAR wszLogDir[] = L"\\AppPatch\\VLog";
  154. WCHAR wszUnicodeHdr = 0xFEFF;
  155. UNICODE_STRING strLogFile;
  156. NTSTATUS status;
  157. OBJECT_ATTRIBUTES ObjectAttributes;
  158. IO_STATUS_BLOCK IoStatusBlock;
  159. //
  160. // Format the log header.
  161. //
  162. if (!GetModuleFileName(NULL, wszModPathName, ARRAYSIZE(wszModPathName))) {
  163. wcscpy(wszModPathName, L"unknown");
  164. }
  165. if (_snwprintf(wszLogHdr,
  166. ARRAYSIZE(wszLogHdr) - 1,
  167. L"%lc<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n<APPLICATION NAME=\"%ls\">\r\n",
  168. wszUnicodeHdr,
  169. wszModPathName) < 0) {
  170. DPFN(eDbgLevelError, "[InitializeLogFile] Buffer too small (1)");
  171. return FALSE;
  172. }
  173. //
  174. // Get the current time and set up the log file name.
  175. // The format of the log file name is this:
  176. // 'processname_registry_yyyymmdd_hhmmss.xml'
  177. //
  178. GetLocalTime(&st);
  179. //
  180. // Extract the name of this module without the path and extension.
  181. // Basically we trim off the extension first (if there is one.)
  182. // Next we find out where the directory path ends, then grab
  183. // the file portion and save it away.
  184. //
  185. wszShortName[0] = 0;
  186. pDot = wcsrchr(wszModPathName, '.');
  187. if (pDot) {
  188. *pDot = '\0';
  189. }
  190. pSlash = wcsrchr(wszModPathName, '\\');
  191. if (pSlash) {
  192. wcsncpy(wszShortName, ++pSlash, (wcslen(pSlash) + 1));
  193. }
  194. if (_snwprintf(wszFileLog,
  195. ARRAYSIZE(wszFileLog) - 1,
  196. L"%ls_registry_%02hu%02hu%02hu_%02hu%02hu%02hu.xml",
  197. wszShortName,
  198. st.wYear,
  199. st.wMonth,
  200. st.wDay,
  201. st.wHour,
  202. st.wMinute,
  203. st.wSecond) < 0) {
  204. DPFN(eDbgLevelError, "[InitializeLogFile] Buffer too small (2)");
  205. return FALSE;
  206. }
  207. //
  208. // Set up the path our log file.
  209. //
  210. nLen = GetSystemWindowsDirectory(NULL, 0);
  211. if (0 == nLen) {
  212. DPFN(eDbgLevelError,
  213. "[InitializeLogFile] %lu Failed to get size for Windows directory path",
  214. GetLastError());
  215. return FALSE;
  216. }
  217. nLen += wcslen(wszFileLog);
  218. nLen += wcslen(wszLogDir);
  219. pwszLogFile = (LPWSTR)MemAlloc((nLen + 2) * sizeof(WCHAR));
  220. if (!pwszLogFile) {
  221. DPFN(eDbgLevelError, "[InitializeLogFile] No memory for log file");
  222. return FALSE;
  223. }
  224. nLen = GetSystemWindowsDirectory(pwszLogFile, (nLen + 2) * sizeof(WCHAR));
  225. if (0 == nLen) {
  226. DPFN(eDbgLevelError,
  227. "[InitializeLogFile] %lu Failed to get Windows directory path",
  228. GetLastError());
  229. return FALSE;
  230. }
  231. wcscat(pwszLogFile, wszLogDir);
  232. //
  233. // Ensure that the %windir%\AppPatch\VLog directory exists.
  234. // If it doesn't, attempt to create it.
  235. //
  236. if (-1 == GetFileAttributes(pwszLogFile)) {
  237. if (!CreateDirectory(pwszLogFile, NULL)) {
  238. DPFN(eDbgLevelError,
  239. "[InitializeLogFile] %lu Failed to create VLog directory",
  240. GetLastError());
  241. return FALSE;
  242. }
  243. }
  244. wcscat(pwszLogFile, L"\\");
  245. wcscat(pwszLogFile, wszFileLog);
  246. //
  247. // Save the pointer as we'll need it later.
  248. //
  249. g_pwszLogFilePath = pwszLogFile;
  250. //
  251. // Attempt to create the new log file.
  252. //
  253. RtlInitUnicodeString(&strLogFile, pwszLogFile);
  254. status = RtlDosPathNameToNtPathName_U(strLogFile.Buffer,
  255. &strLogFile,
  256. NULL,
  257. NULL);
  258. if (!NT_SUCCESS(status)) {
  259. DPFN(eDbgLevelError, "[InitializeLogFile] DOS -> NT failed");
  260. return FALSE;
  261. }
  262. InitializeObjectAttributes(&ObjectAttributes,
  263. &strLogFile,
  264. OBJ_CASE_INSENSITIVE,
  265. NULL,
  266. NULL);
  267. status = NtCreateFile(&hFile,
  268. GENERIC_WRITE | SYNCHRONIZE,
  269. &ObjectAttributes,
  270. &IoStatusBlock,
  271. NULL,
  272. FILE_ATTRIBUTE_NORMAL,
  273. 0,
  274. FILE_CREATE,
  275. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  276. NULL,
  277. 0);
  278. if (!NT_SUCCESS(status)) {
  279. DPFN(eDbgLevelError,
  280. "[InitializeLogFile] 0x%X Failed to create log",
  281. status);
  282. goto cleanup;
  283. }
  284. NtClose(hFile);
  285. //
  286. // Save away the NT path to the file.
  287. //
  288. status = ShimDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
  289. RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING,
  290. &strLogFile,
  291. &g_strLogFilePath);
  292. if (!NT_SUCCESS(status)) {
  293. DPFN(eDbgLevelError,
  294. "[InitializeLogFile] Failed to save log file path");
  295. goto cleanup;
  296. }
  297. //
  298. // Write the header to the log.
  299. //
  300. WriteEntryToLog(wszLogHdr);
  301. fReturn = TRUE;
  302. cleanup:
  303. RtlFreeUnicodeString(&strLogFile);
  304. return fReturn;
  305. }
  306. /*++
  307. Writes the closing element to the file and outputs the log file location.
  308. --*/
  309. BOOL
  310. CloseLogFile(
  311. void
  312. )
  313. {
  314. WCHAR wszBuffer[] = L"</APPLICATION>";
  315. WriteEntryToLog(wszBuffer);
  316. VLOG(VLOG_LEVEL_INFO, VLOG_LOGREGCHANGES_LOGLOC, "%ls", g_pwszLogFilePath);
  317. return TRUE;
  318. }
  319. /*++
  320. Converts from ANSI to Unicode. The caller must free the buffer.
  321. --*/
  322. BOOL
  323. ConvertAnsiToUnicode(
  324. IN LPCSTR pszAnsiString,
  325. OUT LPWSTR* pwszUnicodeString
  326. )
  327. {
  328. int nLen = 0;
  329. nLen = lstrlenA(pszAnsiString);
  330. if (nLen) {
  331. *pwszUnicodeString = (LPWSTR)MemAlloc((nLen + 1) * sizeof(WCHAR));
  332. if (!*pwszUnicodeString) {
  333. DPFN(eDbgLevelError,
  334. "[ConvertAnsiToUnicode] Failed to allocate memory");
  335. return FALSE;
  336. }
  337. nLen = MultiByteToWideChar(CP_ACP,
  338. 0,
  339. pszAnsiString,
  340. -1,
  341. *pwszUnicodeString,
  342. nLen + 1);
  343. if (!nLen) {
  344. DPFN(eDbgLevelError,
  345. "[ConvertAnsiToUnicode] %lu Ansi -> Unicode failed",
  346. GetLastError());
  347. MemFree(*pwszUnicodeString);
  348. return FALSE;
  349. }
  350. }
  351. return TRUE;
  352. }
  353. /*++
  354. Converts a list of NULL terminated strings from ANSI to Unicode.
  355. The caller must free the buffer.
  356. --*/
  357. BOOL
  358. ConvertMultiSzToUnicode(
  359. IN LPCSTR pszAnsiStringList,
  360. OUT LPWSTR* pwszWideStringList
  361. )
  362. {
  363. int nLen = 0;
  364. UINT uSize = 0;
  365. UINT uWideSize = 0;
  366. UINT uTotalSize = 0;
  367. LPCSTR pszAnsi = NULL;
  368. LPWSTR pwszTemp = NULL;
  369. if (!pszAnsiStringList) {
  370. DPFN(eDbgLevelError, "[ConvertMultiSzToUnicode] Invalid parameter");
  371. return FALSE;
  372. }
  373. pszAnsi = pszAnsiStringList;
  374. //
  375. // Determine how large of a buffer we need to allocate.
  376. //
  377. do {
  378. uSize = lstrlenA(pszAnsi) + 1;
  379. uTotalSize += uSize;
  380. pszAnsi += uSize;
  381. } while (uSize != 1);
  382. if (uTotalSize != 0) {
  383. pwszTemp = *pwszWideStringList = (LPWSTR)MemAlloc(uTotalSize * sizeof(WCHAR));
  384. if (!*pwszWideStringList) {
  385. DPFN(eDbgLevelError,
  386. "[ConvertMultiSzToUnicode] No memory for buffer");
  387. return FALSE;
  388. }
  389. }
  390. //
  391. // Perform the ANSI to Unicode conversion.
  392. //
  393. pszAnsi = pszAnsiStringList;
  394. do {
  395. nLen = lstrlenA(pszAnsi) + 1;
  396. uWideSize = MultiByteToWideChar(
  397. CP_ACP,
  398. 0,
  399. pszAnsi,
  400. -1,
  401. pwszTemp,
  402. nLen);
  403. pszAnsi += nLen;
  404. pwszTemp += uWideSize;
  405. } while (nLen != 1);
  406. return TRUE;
  407. }
  408. /*++
  409. Given a predefined key handle such as HKEY_LOCAL_MACHINE, return a string.
  410. --*/
  411. BOOL
  412. PredefinedKeyToString(
  413. IN HKEY hKey,
  414. OUT LPWSTR* pwszString
  415. )
  416. {
  417. if (hKey == HKEY_CLASSES_ROOT) {
  418. wcscpy(*pwszString, L"HKEY_CLASSES_ROOT");
  419. }
  420. else if (hKey == HKEY_CURRENT_CONFIG) {
  421. wcscpy(*pwszString, L"HKEY_CURRENT_CONFIG");
  422. }
  423. else if (hKey == HKEY_CURRENT_USER) {
  424. wcscpy(*pwszString, L"HKEY_CURRENT_USER");
  425. }
  426. else if (hKey == HKEY_LOCAL_MACHINE) {
  427. wcscpy(*pwszString, L"HKEY_LOCAL_MACHINE");
  428. }
  429. else if (hKey == HKEY_USERS) {
  430. wcscpy(*pwszString, L"HKEY_USERS");
  431. }
  432. else if (hKey == HKEY_DYN_DATA) {
  433. wcscpy(*pwszString, L"HKEY_DYN_DATA");
  434. }
  435. else if (hKey == HKEY_PERFORMANCE_DATA) {
  436. wcscpy(*pwszString, L"HKEY_PERFORMANCE_DATA");
  437. }
  438. else {
  439. wcscpy(*pwszString, L"Not recognized");
  440. return FALSE;
  441. }
  442. return TRUE;
  443. }
  444. /*++
  445. Displays the name associated with this object.
  446. --*/
  447. #if DBG
  448. void
  449. PrintNameFromKey(
  450. IN HKEY hKey
  451. )
  452. {
  453. NTSTATUS status;
  454. WCHAR wszBuffer[MAX_PATH];
  455. OBJECT_NAME_INFORMATION *poni = NULL;
  456. wszBuffer[0] = 0;
  457. poni = (OBJECT_NAME_INFORMATION*)wszBuffer;
  458. status = NtQueryObject(hKey, ObjectNameInformation, poni, MAX_PATH, NULL);
  459. if (NT_SUCCESS(status)) {
  460. DPFN(eDbgLevelInfo,
  461. "Key 0x%08x has name: %ls",
  462. hKey,
  463. poni->Name.Buffer);
  464. }
  465. }
  466. #endif // DBG
  467. /*++
  468. Given a pointer to a key node, get the original data.
  469. --*/
  470. BOOL
  471. CLogRegistry::GetOriginalDataForKey(
  472. IN PLOG_OPEN_KEY pLogOpenKey,
  473. IN PKEY_DATA pKeyData,
  474. IN LPCWSTR pwszValueName
  475. )
  476. {
  477. BOOL fReturn = FALSE;
  478. HKEY hKeyLocal;
  479. DWORD cbSize = 0, dwType = 0;
  480. LONG lRetVal;
  481. if (!pLogOpenKey || !pKeyData) {
  482. DPFN(eDbgLevelError, "[GetOriginalDataForKey] Invalid parameter(s)");
  483. return FALSE;
  484. }
  485. lRetVal = RegOpenKeyEx(pLogOpenKey->hKeyRoot,
  486. pLogOpenKey->pwszSubKeyPath,
  487. 0,
  488. KEY_QUERY_VALUE,
  489. &hKeyLocal);
  490. if (ERROR_SUCCESS != lRetVal) {
  491. DPFN(eDbgLevelError, "[GetOriginalDataForKey] Failed to open key");
  492. return FALSE;
  493. }
  494. //
  495. // Query the size of the data. If the data doesn't exist, return success.
  496. //
  497. lRetVal = RegQueryValueEx(hKeyLocal,
  498. pwszValueName,
  499. 0,
  500. &dwType,
  501. NULL,
  502. &cbSize);
  503. if (ERROR_SUCCESS != lRetVal) {
  504. if (ERROR_FILE_NOT_FOUND == lRetVal) {
  505. RegCloseKey(hKeyLocal);
  506. return TRUE;
  507. } else {
  508. DPFN(eDbgLevelError, "[GetOldDataForKey] Failed to get data size");
  509. goto cleanup;
  510. }
  511. }
  512. //
  513. // Update the flags to indicate that the value already exists.
  514. //
  515. pKeyData->dwFlags |= LRC_EXISTING_VALUE;
  516. //
  517. // Allocate a buffer large enough to store the old data.
  518. //
  519. if (dwType != REG_DWORD && dwType != REG_BINARY) {
  520. pKeyData->pOriginalData = (PVOID)MemAlloc(cbSize * sizeof(WCHAR));
  521. pKeyData->cbOriginalDataSize = cbSize * sizeof(WCHAR);
  522. } else {
  523. pKeyData->pOriginalData = (PVOID)MemAlloc(cbSize);
  524. pKeyData->cbOriginalDataSize = cbSize;
  525. }
  526. if (!pKeyData->pOriginalData) {
  527. DPFN(eDbgLevelError,
  528. "[GetOriginalDataForKey] Failed to allocate memory");
  529. goto cleanup;
  530. }
  531. pKeyData->dwOriginalValueType = dwType;
  532. //
  533. // Now make the call again this time getting the actual data.
  534. //
  535. lRetVal = RegQueryValueEx(hKeyLocal,
  536. pwszValueName,
  537. 0,
  538. 0,
  539. (LPBYTE)pKeyData->pOriginalData,
  540. &cbSize);
  541. if (ERROR_SUCCESS != lRetVal) {
  542. DPFN(eDbgLevelError, "[GetOriginalDataForKey] Failed to get data");
  543. goto cleanup;
  544. }
  545. fReturn = TRUE;
  546. cleanup:
  547. RegCloseKey(hKeyLocal);
  548. return fReturn;
  549. }
  550. /*++
  551. Given a pointer to a key node, get the final data.
  552. --*/
  553. BOOL
  554. CLogRegistry::GetFinalDataForKey(
  555. IN PLOG_OPEN_KEY pLogOpenKey,
  556. IN PKEY_DATA pKeyData,
  557. IN LPCWSTR pwszValueName
  558. )
  559. {
  560. BOOL fReturn = FALSE;
  561. HKEY hKeyLocal;
  562. DWORD cbSize = 0, dwType = 0;
  563. LONG lRetVal;
  564. PVOID pTemp = NULL;
  565. if (!pLogOpenKey || !pKeyData) {
  566. DPFN(eDbgLevelError, "[GetFinalDataForKey] Invalid parameter(s)");
  567. return FALSE;
  568. }
  569. lRetVal = RegOpenKeyEx(pLogOpenKey->hKeyRoot,
  570. pLogOpenKey->pwszSubKeyPath,
  571. 0,
  572. KEY_QUERY_VALUE,
  573. &hKeyLocal);
  574. if (ERROR_SUCCESS != lRetVal) {
  575. DPFN(eDbgLevelError, "[GetFinalDataForKey] Failed to open key");
  576. return FALSE;
  577. }
  578. //
  579. // Query the size of the data. If the data doesn't exist, return success.
  580. //
  581. lRetVal = RegQueryValueEx(hKeyLocal,
  582. pwszValueName,
  583. 0,
  584. &dwType,
  585. NULL,
  586. &cbSize);
  587. if (ERROR_SUCCESS != lRetVal) {
  588. if (ERROR_FILE_NOT_FOUND == lRetVal) {
  589. RegCloseKey(hKeyLocal);
  590. return TRUE;
  591. } else {
  592. DPFN(eDbgLevelError,
  593. "[GetFinalDataForKey] Failed to get data size");
  594. goto cleanup;
  595. }
  596. }
  597. //
  598. // It's possible that multiple queries were issued against the same
  599. // key. If this is the case, the buffer to hold the data has already
  600. // been allocated. Determine if the block is large enough.
  601. //
  602. if (pKeyData->pFinalData) {
  603. if (dwType != REG_DWORD && dwType != REG_BINARY) {
  604. //
  605. // If MemReAlloc fails, we would lose the pointer that
  606. // we already had in pKeyData->pFinalData. This preserves
  607. // the pointer.
  608. //
  609. if (pKeyData->cbFinalDataSize < (cbSize * sizeof(WCHAR))) {
  610. pKeyData->cbFinalDataSize = cbSize * sizeof(WCHAR);
  611. pTemp = MemReAlloc(pKeyData->pFinalData,
  612. cbSize * sizeof(WCHAR));
  613. }
  614. } else {
  615. if (pKeyData->cbFinalDataSize < cbSize) {
  616. pKeyData->cbFinalDataSize = cbSize;
  617. pTemp = MemReAlloc(pKeyData->pFinalData,
  618. cbSize);
  619. }
  620. }
  621. if (pTemp) {
  622. pKeyData->pFinalData = pTemp;
  623. } else {
  624. DPFN(eDbgLevelError,
  625. "[GetFinalDataForKey] Failed to reallocate memory");
  626. goto cleanup;
  627. }
  628. } else {
  629. if (dwType != REG_DWORD && dwType != REG_BINARY) {
  630. pKeyData->pFinalData = MemAlloc(cbSize * sizeof(WCHAR));
  631. pKeyData->cbFinalDataSize = cbSize * sizeof(WCHAR);
  632. } else {
  633. pKeyData->pFinalData = MemAlloc(cbSize);
  634. pKeyData->cbFinalDataSize = cbSize;
  635. }
  636. }
  637. if (!pKeyData->pFinalData) {
  638. DPFN(eDbgLevelError, "[GetFinalDataForKey] Failed to allocate memory");
  639. goto cleanup;
  640. }
  641. pKeyData->dwFinalValueType = dwType;
  642. //
  643. // Now make the call again this time getting the actual data.
  644. //
  645. lRetVal = RegQueryValueEx(hKeyLocal,
  646. pwszValueName,
  647. 0,
  648. 0,
  649. (LPBYTE)pKeyData->pFinalData,
  650. &cbSize);
  651. if (ERROR_SUCCESS != lRetVal) {
  652. DPFN(eDbgLevelError, "[GetFinalDataForKey] Failed to get data");
  653. goto cleanup;
  654. }
  655. fReturn = TRUE;
  656. cleanup:
  657. RegCloseKey(hKeyLocal);
  658. return fReturn;
  659. }
  660. /*++
  661. Given a value name, attempt to find it in the list.
  662. This function may not always return a pointer.
  663. --*/
  664. PKEY_DATA
  665. CLogRegistry::FindValueNameInList(
  666. IN LPCWSTR pwszValueName,
  667. IN PLOG_OPEN_KEY pOpenKey
  668. )
  669. {
  670. BOOL fFound = FALSE;
  671. PLIST_ENTRY pHead = NULL;
  672. PLIST_ENTRY pNext = NULL;
  673. PKEY_DATA pFindData = NULL;
  674. if (!pwszValueName || !pOpenKey) {
  675. DPFN(eDbgLevelError, "[FindValueNameInList] Invalid parameter(s)");
  676. return NULL;
  677. }
  678. pHead = &pOpenKey->KeyData;
  679. pNext = pHead->Flink;
  680. while (pNext != pHead) {
  681. pFindData = CONTAINING_RECORD(pNext, KEY_DATA, Entry);
  682. if (!_wcsicmp(pwszValueName, pFindData->wszValueName)) {
  683. fFound = TRUE;
  684. break;
  685. }
  686. pNext = pNext->Flink;
  687. }
  688. return (fFound ? pFindData : NULL);
  689. }
  690. /*++
  691. Given a key path, attempt to locate it in the list.
  692. This function may not always return a pointer.
  693. --*/
  694. PLOG_OPEN_KEY
  695. CLogRegistry::FindKeyPathInList(
  696. IN LPCWSTR pwszKeyPath
  697. )
  698. {
  699. BOOL fFound = FALSE;
  700. PLIST_ENTRY pCurrent = NULL;
  701. PLOG_OPEN_KEY pFindKey = NULL;
  702. if (!pwszKeyPath) {
  703. DPFN(eDbgLevelError, "[FindKeyPathInList] Invalid parameter");
  704. return NULL;
  705. }
  706. //
  707. // Attempt to locate the entry in the list.
  708. //
  709. pCurrent = g_OpenKeyListHead.Flink;
  710. while (pCurrent != &g_OpenKeyListHead) {
  711. pFindKey = CONTAINING_RECORD(pCurrent, LOG_OPEN_KEY, Entry);
  712. if (pFindKey->pwszFullKeyPath) {
  713. if (!_wcsicmp(pwszKeyPath, pFindKey->pwszFullKeyPath)) {
  714. fFound = TRUE;
  715. break;
  716. }
  717. }
  718. pCurrent = pCurrent->Flink;
  719. }
  720. return (fFound ? pFindKey : NULL);
  721. }
  722. /*++
  723. Given a key handle, remove it from the array in the list.
  724. --*/
  725. PLOG_OPEN_KEY
  726. CLogRegistry::RemoveKeyHandleFromArray(
  727. IN HKEY hKey
  728. )
  729. {
  730. UINT uCount;
  731. PLIST_ENTRY pCurrent = NULL;
  732. PLOG_OPEN_KEY pFindKey = NULL;
  733. if (!hKey) {
  734. DPFN(eDbgLevelError,
  735. "[RemoveKeyHandleFromArray] Invalid key handle passed!");
  736. return NULL;
  737. }
  738. pCurrent = g_OpenKeyListHead.Flink;
  739. while (pCurrent != &g_OpenKeyListHead) {
  740. pFindKey = CONTAINING_RECORD(pCurrent, LOG_OPEN_KEY, Entry);
  741. //
  742. // Step through this guy's array looking for the handle.
  743. //
  744. for (uCount = 0; uCount < pFindKey->cHandles; uCount++) {
  745. //
  746. // If we find the handle, set the array element to NULL and
  747. // decrement the count of handles for this entry.
  748. //
  749. if (pFindKey->hKeyBase[uCount] == hKey) {
  750. DPFN(eDbgLevelInfo,
  751. "[RemoveKeyHandleFromArray] Removing handle 0x%08x",
  752. hKey);
  753. pFindKey->hKeyBase[uCount] = NULL;
  754. pFindKey->cHandles--;
  755. return pFindKey;
  756. }
  757. }
  758. pCurrent = pCurrent->Flink;
  759. }
  760. return NULL;
  761. }
  762. /*++
  763. Finds a key handle in the array.
  764. --*/
  765. PLOG_OPEN_KEY
  766. CLogRegistry::FindKeyHandleInArray(
  767. IN HKEY hKey
  768. )
  769. {
  770. UINT uCount;
  771. BOOL fFound = FALSE;
  772. PLOG_OPEN_KEY pFindKey = NULL;
  773. PLIST_ENTRY pCurrent = NULL;
  774. if (!hKey) {
  775. DPFN(eDbgLevelError,
  776. "[FindKeyHandleInArray] Invalid key handle passed!");
  777. return NULL;
  778. }
  779. pCurrent = g_OpenKeyListHead.Flink;
  780. while (pCurrent != &g_OpenKeyListHead) {
  781. pFindKey = CONTAINING_RECORD(pCurrent, LOG_OPEN_KEY, Entry);
  782. //
  783. // Step through this guy's array looking for the handle.
  784. //
  785. for (uCount = 0; uCount < pFindKey->cHandles; uCount++) {
  786. if (pFindKey->hKeyBase[uCount] == hKey) {
  787. fFound = TRUE;
  788. break;
  789. }
  790. }
  791. if (fFound) {
  792. break;
  793. }
  794. pCurrent = pCurrent->Flink;
  795. }
  796. #if DBG
  797. if (!fFound) {
  798. //
  799. // Dear God - the key handle is not in the list!
  800. // Break into the debugger on checked builds.
  801. //
  802. DPFN(eDbgLevelError,
  803. "[FindKeyHandleInArray] Key 0x%08x not in list!",
  804. hKey);
  805. PrintNameFromKey(hKey);
  806. DbgBreakPoint();
  807. }
  808. #endif // DBG
  809. return (fFound ? pFindKey : NULL);
  810. }
  811. /*++
  812. Given a predefined handle and a subkey path,
  813. open the key to force it into the list.
  814. --*/
  815. HKEY
  816. CLogRegistry::ForceSubKeyIntoList(
  817. IN HKEY hKeyPredefined,
  818. IN LPCWSTR pwszSubKey
  819. )
  820. {
  821. LONG lRetVal;
  822. HKEY hKeyRet;
  823. if (!pwszSubKey) {
  824. DPFN(eDbgLevelError, "[ForceSubKeyIntoList] Invalid parameter");
  825. return NULL;
  826. }
  827. lRetVal = OpenKeyExW(hKeyPredefined,
  828. pwszSubKey,
  829. 0,
  830. KEY_WRITE,
  831. &hKeyRet);
  832. if (ERROR_SUCCESS != lRetVal) {
  833. DPFN(eDbgLevelError, "[ForceSubKeyIntoList] Failed to open key");
  834. return NULL;
  835. }
  836. return hKeyRet;
  837. }
  838. /*++
  839. Add a non-predefined key handle to the array.
  840. --*/
  841. PLOG_OPEN_KEY
  842. CLogRegistry::AddKeyHandleToList(
  843. IN HKEY hKey,
  844. IN HKEY hKeyNew,
  845. IN LPCWSTR pwszSubKeyPath,
  846. IN BOOL fExisting
  847. )
  848. {
  849. UINT uCount;
  850. DWORD dwLen = 0;
  851. PLOG_OPEN_KEY pFindKey = NULL;
  852. PLOG_OPEN_KEY pRetKey = NULL;
  853. PLOG_OPEN_KEY pExistingFindKey = NULL;
  854. //
  855. // If hKeyNew, which is the key handle the caller received
  856. // from the function, is a predefined handle, we simply
  857. // call FindKeyInArray, which will return a pointer to the
  858. // list entry that contains that key handle. These handles
  859. // were added during initialization, so there's no chance
  860. // that the caller won't get a pointer back.
  861. //
  862. if (IsPredefinedRegistryHandle(hKeyNew)) {
  863. return FindKeyHandleInArray(hKeyNew);
  864. }
  865. //
  866. // We've got a usual case where a key has been opened, and
  867. // now the caller is opening a subkey underneath it.
  868. //
  869. pFindKey = FindKeyHandleInArray(hKey);
  870. //
  871. // If pFindKey ever comes back as NULL, something is really
  872. // wrong. Every OpenKey/CreateKey comes through us and goes
  873. // into the list (with the exception of predefined handles
  874. // which are already stored there.) Dump out as much data
  875. // as we can to figure out what went wrong.
  876. //
  877. if (!pFindKey) {
  878. DPFN(eDbgLevelError,
  879. "[AddKeyHandleToList] Key not found in list! Key Handle = 0x%08x New key = 0x%08x Path = %ls",
  880. hKey, hKeyNew, pwszSubKeyPath);
  881. return NULL;
  882. }
  883. pRetKey = (PLOG_OPEN_KEY)MemAlloc(sizeof(LOG_OPEN_KEY));
  884. if (!pRetKey) {
  885. DPFN(eDbgLevelError, "[AddKeyHandleToList] No memory available");
  886. return NULL;
  887. }
  888. //
  889. // Make room for the subkey path that will go into the new
  890. // node. If the node that we found has a subkey path stored,
  891. // take that into account also.
  892. //
  893. if (pwszSubKeyPath) {
  894. dwLen = wcslen(pwszSubKeyPath);
  895. }
  896. if (pFindKey->pwszSubKeyPath) {
  897. dwLen += wcslen(pFindKey->pwszSubKeyPath);
  898. }
  899. if (pFindKey->pwszSubKeyPath || pwszSubKeyPath) {
  900. pRetKey->pwszSubKeyPath = (LPWSTR)MemAlloc((dwLen + 2) * sizeof(WCHAR));
  901. if (!pRetKey->pwszSubKeyPath) {
  902. DPFN(eDbgLevelError, "[AddKeyHandleToList] No memory for subkey path");
  903. goto cleanup;
  904. }
  905. }
  906. //
  907. // If the node that we found has a subkey path, take it
  908. // and copy it over to the new node and concatenate
  909. // the subkey path that we got passed. Otherwise just
  910. // store the path that was passed, if available.
  911. //
  912. if (pFindKey->pwszSubKeyPath && pwszSubKeyPath) {
  913. wcscpy(pRetKey->pwszSubKeyPath, pFindKey->pwszSubKeyPath);
  914. wcscat(pRetKey->pwszSubKeyPath, L"\\");
  915. wcscat(pRetKey->pwszSubKeyPath, pwszSubKeyPath);
  916. } else if (pwszSubKeyPath) {
  917. wcscpy(pRetKey->pwszSubKeyPath, pwszSubKeyPath);
  918. }
  919. //
  920. // Make room for the full key path. This will store a path
  921. // of something like HKEY_LOCAL_MACHINE\Software\Microsoft...
  922. // that will be used for logging purposes.
  923. //
  924. if (pRetKey->pwszSubKeyPath) {
  925. dwLen = wcslen(pRetKey->pwszSubKeyPath);
  926. }
  927. pRetKey->pwszFullKeyPath = (LPWSTR)MemAlloc((dwLen + 2 + MAX_ROOT_LENGTH) * sizeof(WCHAR));
  928. if (!pRetKey->pwszFullKeyPath) {
  929. DPFN(eDbgLevelError,
  930. "[AddKeyHandleToList] No memory for full key path");
  931. goto cleanup;
  932. }
  933. //
  934. // Convert the predefined handle to a string and store it in
  935. // the node that we're about to add to the list.
  936. //
  937. if (!PredefinedKeyToString(pFindKey->hKeyRoot, &pRetKey->pwszFullKeyPath)) {
  938. DPFN(eDbgLevelError,
  939. "[AddKeyHandleToList] PredefinedKey -> String failed");
  940. goto cleanup;
  941. }
  942. if (pwszSubKeyPath) {
  943. wcscat(pRetKey->pwszFullKeyPath, L"\\");
  944. wcscat(pRetKey->pwszFullKeyPath, pRetKey->pwszSubKeyPath);
  945. }
  946. //
  947. // At this point we have a full key path.
  948. // We attempt to find the path in the linked list.
  949. // If we find it, we're going to update the handle array and count for this guy.
  950. // If we don't find it, we're going to add a new entry to the list.
  951. //
  952. pExistingFindKey = FindKeyPathInList(pRetKey->pwszFullKeyPath);
  953. if (!pExistingFindKey) {
  954. //
  955. // Fill in information about this key and add it to the list.
  956. //
  957. pRetKey->hKeyBase[0] = hKeyNew;
  958. pRetKey->hKeyRoot = pFindKey->hKeyRoot;
  959. pRetKey->cHandles = 1;
  960. pRetKey->dwFlags |= fExisting ? LRC_EXISTING_KEY : 0;
  961. InitializeListHead(&pRetKey->KeyData);
  962. DPFN(eDbgLevelInfo, "[AddKeyHandleToList] Adding key: %p", pRetKey);
  963. InsertHeadList(&g_OpenKeyListHead, &pRetKey->Entry);
  964. return pRetKey;
  965. } else {
  966. //
  967. // Store this handle in the array and increment the handle count.
  968. // Make sure we don't overstep the array bounds.
  969. //
  970. for (uCount = 0; uCount < pExistingFindKey->cHandles; uCount++) {
  971. if (NULL == pExistingFindKey->hKeyBase[uCount]) {
  972. break;
  973. }
  974. }
  975. if (uCount >= MAX_NUM_HANDLES) {
  976. DPFN(eDbgLevelError, "[AddKeyHandleToList] Handle count reached");
  977. goto cleanup;
  978. }
  979. pExistingFindKey->hKeyBase[uCount] = hKeyNew;
  980. pExistingFindKey->dwFlags &= ~LRC_DELETED_KEY;
  981. pExistingFindKey->cHandles++;
  982. }
  983. cleanup:
  984. if (pRetKey->pwszFullKeyPath) {
  985. MemFree(pRetKey->pwszFullKeyPath);
  986. }
  987. if (pRetKey) {
  988. MemFree(pRetKey);
  989. }
  990. return pExistingFindKey;
  991. }
  992. /*++
  993. Add a value to the list.
  994. --*/
  995. PKEY_DATA
  996. CLogRegistry::AddValueNameToList(
  997. IN PLOG_OPEN_KEY pLogOpenKey,
  998. IN LPCWSTR pwszValueName
  999. )
  1000. {
  1001. PKEY_DATA pKeyData = NULL;
  1002. pKeyData = (PKEY_DATA)MemAlloc(sizeof(KEY_DATA));
  1003. if (!pKeyData) {
  1004. DPFN(eDbgLevelError, "[AddValueNameToList] Failed to allocate memory");
  1005. return NULL;
  1006. }
  1007. if (!GetOriginalDataForKey(pLogOpenKey, pKeyData, pwszValueName)) {
  1008. DPFN(eDbgLevelError,
  1009. "[AddValueNameToList] Failed to get original data");
  1010. goto cleanup;
  1011. }
  1012. if (pwszValueName) {
  1013. wcsncpy(pKeyData->wszValueName, pwszValueName, MAX_PATH);
  1014. } else {
  1015. //
  1016. // If the valuename is NULL, assign our unique id.
  1017. //
  1018. wcsncpy(pKeyData->wszValueName, g_wszUniqueId, wcslen(g_wszUniqueId));
  1019. }
  1020. InsertHeadList(&pLogOpenKey->KeyData, &pKeyData->Entry);
  1021. return pKeyData;
  1022. cleanup:
  1023. if (pKeyData) {
  1024. MemFree(pKeyData);
  1025. }
  1026. return NULL;
  1027. }
  1028. /*++
  1029. The entry point for modifying the linked list data.
  1030. --*/
  1031. PLOG_OPEN_KEY
  1032. CLogRegistry::UpdateKeyList(
  1033. IN HKEY hKeyRoot,
  1034. IN HKEY hKeyNew,
  1035. IN LPCWSTR pwszSubKey,
  1036. IN LPCWSTR pwszValueName,
  1037. IN BOOL fExisting,
  1038. IN UpdateType eType
  1039. )
  1040. {
  1041. PKEY_DATA pKeyData = NULL;
  1042. PLOG_OPEN_KEY pRetKey = NULL;
  1043. switch (eType) {
  1044. case eAddKeyHandle:
  1045. pRetKey = AddKeyHandleToList(hKeyRoot, hKeyNew, pwszSubKey, fExisting);
  1046. break;
  1047. case eRemoveKeyHandle:
  1048. pRetKey = RemoveKeyHandleFromArray(hKeyNew);
  1049. break;
  1050. case eStartModifyValue:
  1051. case eStartDeleteValue:
  1052. pRetKey = FindKeyHandleInArray(hKeyNew);
  1053. if (!pRetKey) {
  1054. DPFN(eDbgLevelError,
  1055. "[UpdateKeyList] Start Modify: Failed to find handle in array");
  1056. break;
  1057. }
  1058. if (!pwszValueName) {
  1059. pKeyData = FindValueNameInList(g_wszUniqueId, pRetKey);
  1060. } else {
  1061. pKeyData = FindValueNameInList(pwszValueName, pRetKey);
  1062. }
  1063. if (pKeyData) {
  1064. //
  1065. // If the caller is attempting to modify the value, and we've
  1066. // already gotten data for it, don't do it again.
  1067. // Also, if they're attempting to delete the value, and it's
  1068. // been modified, don't do it again.
  1069. //
  1070. if ((pKeyData->pOriginalData || pKeyData->pFinalData) ||
  1071. (pKeyData->dwFlags & LRC_MODIFIED_VALUE) &&
  1072. (eStartDeleteValue == eType)) {
  1073. break;
  1074. }
  1075. if (!GetOriginalDataForKey(pRetKey, pKeyData, pwszValueName)) {
  1076. DPFN(eDbgLevelError,
  1077. "[UpdateKeyList] Start Modify: Failed to get original data");
  1078. break;
  1079. }
  1080. } else {
  1081. //
  1082. // We've never seen this value before. Insert it into the list.
  1083. //
  1084. if (!AddValueNameToList(pRetKey, pwszValueName)) {
  1085. DPFN(eDbgLevelError,
  1086. "[UpdateKeyList] Start Modify: Failed to insert value");
  1087. break;
  1088. }
  1089. }
  1090. break;
  1091. case eEndModifyValue:
  1092. case eEndDeleteValue:
  1093. pRetKey = FindKeyHandleInArray(hKeyNew);
  1094. if (!pRetKey) {
  1095. DPFN(eDbgLevelError,
  1096. "[UpdateKeyList] End Modify: Failed to find handle in array");
  1097. break;
  1098. }
  1099. if (!pwszValueName) {
  1100. pKeyData = FindValueNameInList(g_wszUniqueId, pRetKey);
  1101. } else {
  1102. pKeyData = FindValueNameInList(pwszValueName, pRetKey);
  1103. }
  1104. if (!pKeyData) {
  1105. DPFN(eDbgLevelError,
  1106. "[UpdateKeyList] End Modify: Failed to find value in list");
  1107. break;
  1108. }
  1109. if (eEndModifyValue == eType) {
  1110. if (!GetFinalDataForKey(pRetKey, pKeyData, pwszValueName)) {
  1111. DPFN(eDbgLevelError,
  1112. "[UpdateKeyList] End Modify: Failed to get final data");
  1113. break;
  1114. }
  1115. pKeyData->dwFlags |= LRC_MODIFIED_VALUE;
  1116. }
  1117. else if (eEndDeleteValue == eType) {
  1118. pKeyData->dwFlags |= LRC_DELETED_VALUE;
  1119. }
  1120. break;
  1121. case eDeletedKey:
  1122. pRetKey = FindKeyHandleInArray(hKeyNew);
  1123. if (!pRetKey) {
  1124. DPFN(eDbgLevelError,
  1125. "[UpdateKeyList] DeleteKey: Failed to find handle in array");
  1126. break;
  1127. }
  1128. pRetKey->dwFlags |= LRC_DELETED_KEY;
  1129. break;
  1130. default:
  1131. DPFN(eDbgLevelError, "[UpdateKeyList] Invalid enum type!");
  1132. break;
  1133. }
  1134. return pRetKey;
  1135. }
  1136. /*++
  1137. Formats the data to form an XML element and logs it.
  1138. --*/
  1139. void
  1140. FormatKeyDataIntoElement(
  1141. IN LPCWSTR pwszOperation,
  1142. IN PLOG_OPEN_KEY pLogOpenKey
  1143. )
  1144. {
  1145. UINT cbSize = 0;
  1146. PVOID pTemp = NULL;
  1147. //
  1148. // To make it easier to replace & ' " < and > with their
  1149. // XML entities, we convert the data to CString.
  1150. //
  1151. CString csFullKeyPath(pLogOpenKey->pwszFullKeyPath);
  1152. csFullKeyPath.Replace(L"&", L"&amp;");
  1153. csFullKeyPath.Replace(L"<", L"&lt;");
  1154. csFullKeyPath.Replace(L">", L"&gt;");
  1155. csFullKeyPath.Replace(L"'", L"&apos;");
  1156. csFullKeyPath.Replace(L"\"", L"&quot;");
  1157. //
  1158. // To keep allocations to a minimum, we allocate a global
  1159. // buffer one time, then reallocate if the data we're
  1160. // logging is larger than the buffer.
  1161. //
  1162. if (!g_cbTempBufferSize) {
  1163. g_pwszTempBuffer = (LPWSTR)MemAlloc(TEMP_BUFFER_SIZE * sizeof(WCHAR));
  1164. if (!g_pwszTempBuffer) {
  1165. DPFN(eDbgLevelError, "[FormatKeyData] Failed to allocate memory");
  1166. return;
  1167. }
  1168. g_cbTempBufferSize = TEMP_BUFFER_SIZE * sizeof(WCHAR);
  1169. }
  1170. g_pwszTempBuffer[0] = 0;
  1171. //
  1172. // Determine how large of a buffer we'll need.
  1173. //
  1174. cbSize += csFullKeyPath.GetLength();
  1175. cbSize += MAX_OPERATION_LENGTH;
  1176. cbSize += KEY_ELEMENT_SIZE;
  1177. cbSize *= sizeof(WCHAR);
  1178. if (cbSize > g_cbTempBufferSize) {
  1179. //
  1180. // Our global buffer is not large enough; reallocate.
  1181. //
  1182. pTemp = (LPWSTR)MemReAlloc(g_pwszTempBuffer,
  1183. cbSize + BUFFER_ALLOCATION_DELTA);
  1184. if (pTemp) {
  1185. g_pwszTempBuffer = (LPWSTR)pTemp;
  1186. } else {
  1187. DPFN(eDbgLevelError,
  1188. "[FormatKeyData] Failed to reallocate memory");
  1189. return;
  1190. }
  1191. g_cbTempBufferSize = cbSize + BUFFER_ALLOCATION_DELTA;
  1192. }
  1193. wsprintf(g_pwszTempBuffer,
  1194. L" <OPERATION TYPE=\"%ls\" KEY_PATH=\"%ls\"/>\r\n",
  1195. pwszOperation,
  1196. csFullKeyPath.Get());
  1197. WriteEntryToLog(g_pwszTempBuffer);
  1198. }
  1199. void
  1200. FormatValueDataIntoElement(
  1201. IN CString& csFullKeyPath,
  1202. IN LPCWSTR pwszOperation,
  1203. IN LPCWSTR pwszValueName,
  1204. IN LPCWSTR pwszOriginalValueType,
  1205. IN LPCWSTR pwszFinalValueType
  1206. )
  1207. {
  1208. UINT cbSize = 0;
  1209. int nChars = 0;
  1210. PVOID pTemp = NULL;
  1211. //
  1212. // To keep allocations to a minimum, we allocate a global
  1213. // buffer one time, then reallocate if the data we're
  1214. // logging is larger than the buffer.
  1215. //
  1216. if (!g_cbTempBufferSize) {
  1217. g_pwszTempBuffer = (LPWSTR)MemAlloc(TEMP_BUFFER_SIZE * sizeof(WCHAR));
  1218. if (!g_pwszTempBuffer) {
  1219. DPFN(eDbgLevelError,
  1220. "[FormatValueDataIntoElement] Failed to allocate memory");
  1221. return;
  1222. }
  1223. g_cbTempBufferSize = TEMP_BUFFER_SIZE * sizeof(WCHAR);
  1224. }
  1225. //
  1226. // Determine how large of a buffer we'll need.
  1227. //
  1228. cbSize += wcslen(pwszOperation);
  1229. cbSize += wcslen(pwszOriginalValueType);
  1230. cbSize += wcslen(pwszFinalValueType);
  1231. cbSize += wcslen(g_pwszOriginalData);
  1232. cbSize += wcslen(g_pwszFinalData);
  1233. cbSize += csFullKeyPath.GetLength();
  1234. cbSize += VALUE_ELEMENT_SIZE;
  1235. if (pwszValueName) {
  1236. cbSize += wcslen(pwszValueName);
  1237. }
  1238. cbSize *= sizeof(WCHAR);
  1239. if (cbSize > g_cbTempBufferSize) {
  1240. //
  1241. // Our global buffer is not large enough; reallocate.
  1242. //
  1243. pTemp = (LPWSTR)MemReAlloc(g_pwszTempBuffer,
  1244. cbSize + BUFFER_ALLOCATION_DELTA);
  1245. if (pTemp) {
  1246. g_pwszTempBuffer = (LPWSTR)pTemp;
  1247. } else {
  1248. DPFN(eDbgLevelError,
  1249. "[FormatValueDataIntoElement] Failed to reallocate memory");
  1250. return;
  1251. }
  1252. g_cbTempBufferSize = cbSize + BUFFER_ALLOCATION_DELTA;
  1253. }
  1254. //
  1255. // Open the <OPERATION> element.
  1256. //
  1257. nChars = wsprintf(g_pwszTempBuffer, L" <OPERATION TYPE=\"%ls\" KEY_PATH=\"%ls\">\r\n",
  1258. pwszOperation,
  1259. csFullKeyPath.Get());
  1260. //
  1261. // Write the <VALUE_NAME> element.
  1262. //
  1263. if (pwszValueName) {
  1264. nChars += wsprintf(g_pwszTempBuffer + nChars, L" <VALUE_NAME><![CDATA[%ls]]></VALUE_NAME>\r\n",
  1265. pwszValueName);
  1266. } else {
  1267. nChars += wsprintf(g_pwszTempBuffer + nChars, L" <VALUE_NAME/>\r\n");
  1268. }
  1269. //
  1270. // Write the <ORIGINAL_DATA> element.
  1271. //
  1272. if (g_pwszOriginalData[0]) {
  1273. nChars += wsprintf(g_pwszTempBuffer + nChars, L" <ORIGINAL_DATA TYPE=\"%ls\"><![CDATA[%ls]]></ORIGINAL_DATA>\r\n",
  1274. pwszOriginalValueType,
  1275. g_pwszOriginalData);
  1276. } else {
  1277. nChars += wsprintf(g_pwszTempBuffer + nChars, L" <ORIGINAL_DATA/>\r\n");
  1278. }
  1279. //
  1280. // Write the <FINAL_DATA> element.
  1281. //
  1282. if (g_pwszFinalData[0]) {
  1283. nChars += wsprintf(g_pwszTempBuffer + nChars, L" <FINAL_DATA TYPE=\"%ls\"><![CDATA[%ls]]></FINAL_DATA>\r\n",
  1284. pwszFinalValueType,
  1285. g_pwszFinalData);
  1286. } else {
  1287. nChars += wsprintf(g_pwszTempBuffer + nChars, L" <FINAL_DATA/>\r\n");
  1288. }
  1289. //
  1290. // Close the <OPERATION> element.
  1291. //
  1292. wsprintf(g_pwszTempBuffer + nChars, L" </OPERATION>\r\n");
  1293. WriteEntryToLog(g_pwszTempBuffer);
  1294. return;
  1295. }
  1296. /*++
  1297. Converts binary data into a readable string.
  1298. --*/
  1299. void
  1300. ExtractBinaryData(
  1301. IN PVOID pBinary,
  1302. IN DWORD dwDataSize,
  1303. IN OUT LPWSTR* pwszString
  1304. )
  1305. {
  1306. int nChars = 0;
  1307. PBYTE pByte = NULL;
  1308. DWORD dwLoop = 0;
  1309. if (!pBinary || !pwszString) {
  1310. DPFN(eDbgLevelError, "[ExtractBinaryData] Invalid parameter(s)");
  1311. return;
  1312. }
  1313. pByte = (BYTE*)pBinary;
  1314. dwLoop = dwDataSize / sizeof(WCHAR);
  1315. while (dwLoop) {
  1316. nChars += wsprintf(*pwszString + nChars, L"%lx", *pByte++);
  1317. dwLoop--;
  1318. }
  1319. }
  1320. /*++
  1321. Converts a REG_MULTI_SZ to a readable string.
  1322. --*/
  1323. void
  1324. ExtractMultiSzStrings(
  1325. IN PVOID pMultiSz,
  1326. IN OUT LPWSTR* pwszString
  1327. )
  1328. {
  1329. int nChars = 0;
  1330. UINT uSize = 0;
  1331. LPWSTR pwszTmp = NULL;
  1332. if (!pMultiSz || !pwszString) {
  1333. DPFN(eDbgLevelError, "[ExtractMultiSzStrings] Invalid parameter(s)");
  1334. return;
  1335. }
  1336. //
  1337. // Walk the list of NULL-terminated strings and put them in the buffer.
  1338. //
  1339. pwszTmp = (LPWSTR)pMultiSz;
  1340. while (TRUE) {
  1341. nChars += wsprintf(*pwszString + nChars, L" %ls", pwszTmp);
  1342. uSize = wcslen(pwszTmp) + 1;
  1343. pwszTmp += uSize;
  1344. if (*pwszTmp == '\0') {
  1345. break;
  1346. }
  1347. }
  1348. }
  1349. /*++
  1350. Formats the value data to form an XML element and logs it.
  1351. --*/
  1352. void
  1353. FormatValueData(
  1354. IN LPCWSTR pwszOperation,
  1355. IN PKEY_DATA pKeyData,
  1356. IN PLOG_OPEN_KEY pLogOpenKey
  1357. )
  1358. {
  1359. WCHAR wszFinalValueType[MAX_DATA_TYPE_LENGTH];
  1360. WCHAR wszOriginalValueType[MAX_DATA_TYPE_LENGTH];
  1361. LPCWSTR pwszValueName = NULL;
  1362. PVOID pOriginalTmp = NULL;
  1363. PVOID pFinalTmp = NULL;
  1364. //
  1365. // If we haven't already, allocate buffers that we'll
  1366. // use and reuse when getting original and final data.
  1367. //
  1368. if (!g_cbOriginalDataBufferSize) {
  1369. g_pwszOriginalData = (LPWSTR)MemAlloc(TEMP_BUFFER_SIZE * sizeof(WCHAR));
  1370. if (!g_pwszOriginalData) {
  1371. DPFN(eDbgLevelError,
  1372. "[FormatValueData] Failed to allocate memory for old data");
  1373. return;
  1374. }
  1375. g_cbOriginalDataBufferSize = TEMP_BUFFER_SIZE * sizeof(WCHAR);
  1376. }
  1377. if (!g_cbFinalDataBufferSize) {
  1378. g_pwszFinalData = (LPWSTR)MemAlloc(TEMP_BUFFER_SIZE * sizeof(WCHAR));
  1379. if (!g_pwszFinalData) {
  1380. DPFN(eDbgLevelError,
  1381. "[FormatValueData] Failed to allocate memory for new data");
  1382. return;
  1383. }
  1384. g_cbFinalDataBufferSize = TEMP_BUFFER_SIZE * sizeof(WCHAR);
  1385. }
  1386. g_pwszOriginalData[0] = 0;
  1387. g_pwszFinalData[0] = 0;
  1388. //
  1389. // To make it easier to replace & ' " < and > with their
  1390. // XML entities, we convert the data to CString.
  1391. //
  1392. CString csFullKeyPath(pLogOpenKey->pwszFullKeyPath);
  1393. csFullKeyPath.Replace(L"&", L"&amp;");
  1394. csFullKeyPath.Replace(L"<", L"&lt;");
  1395. csFullKeyPath.Replace(L">", L"&gt;");
  1396. csFullKeyPath.Replace(L"'", L"&apos;");
  1397. csFullKeyPath.Replace(L"\"", L"&quot;");
  1398. switch (pKeyData->dwOriginalValueType) {
  1399. case REG_SZ:
  1400. wcscpy(wszOriginalValueType, L"REG_SZ");
  1401. break;
  1402. case REG_EXPAND_SZ:
  1403. wcscpy(wszOriginalValueType, L"REG_EXPAND_SZ");
  1404. break;
  1405. case REG_MULTI_SZ:
  1406. wcscpy(wszOriginalValueType, L"REG_MULTI_SZ");
  1407. break;
  1408. case REG_DWORD:
  1409. wcscpy(wszOriginalValueType, L"REG_DWORD");
  1410. break;
  1411. case REG_BINARY:
  1412. wcscpy(wszOriginalValueType, L"REG_BINARY");
  1413. break;
  1414. default:
  1415. wcscpy(wszOriginalValueType, L"Unknown");
  1416. break;
  1417. }
  1418. switch (pKeyData->dwFinalValueType) {
  1419. case REG_SZ:
  1420. wcscpy(wszFinalValueType, L"REG_SZ");
  1421. break;
  1422. case REG_EXPAND_SZ:
  1423. wcscpy(wszFinalValueType, L"REG_EXPAND_SZ");
  1424. break;
  1425. case REG_MULTI_SZ:
  1426. wcscpy(wszFinalValueType, L"REG_MULTI_SZ");
  1427. break;
  1428. case REG_DWORD:
  1429. wcscpy(wszFinalValueType, L"REG_DWORD");
  1430. break;
  1431. case REG_BINARY:
  1432. wcscpy(wszFinalValueType, L"REG_BINARY");
  1433. break;
  1434. default:
  1435. wcscpy(wszFinalValueType, L"Unknown");
  1436. break;
  1437. }
  1438. //
  1439. // If our temporary buffers are not large enough to store the data, reallocate.
  1440. //
  1441. if (pKeyData->cbOriginalDataSize > g_cbOriginalDataBufferSize) {
  1442. pOriginalTmp = (LPWSTR)MemReAlloc(g_pwszOriginalData,
  1443. pKeyData->cbOriginalDataSize + BUFFER_ALLOCATION_DELTA);
  1444. if (pOriginalTmp) {
  1445. g_pwszOriginalData = (LPWSTR)pOriginalTmp;
  1446. } else {
  1447. DPFN(eDbgLevelError,
  1448. "[FormatValueData] Failed to reallocate for original data");
  1449. return;
  1450. }
  1451. g_cbOriginalDataBufferSize = pKeyData->cbOriginalDataSize + BUFFER_ALLOCATION_DELTA;
  1452. }
  1453. if (pKeyData->cbFinalDataSize > g_cbFinalDataBufferSize) {
  1454. pFinalTmp = (LPWSTR)MemReAlloc(g_pwszFinalData,
  1455. pKeyData->cbFinalDataSize + BUFFER_ALLOCATION_DELTA);
  1456. if (pFinalTmp) {
  1457. g_pwszFinalData = (LPWSTR)pFinalTmp;
  1458. } else {
  1459. DPFN(eDbgLevelError,
  1460. "[FormatValueData] Failed to reallocate for new data");
  1461. return;
  1462. }
  1463. g_cbFinalDataBufferSize = pKeyData->cbFinalDataSize + BUFFER_ALLOCATION_DELTA;
  1464. }
  1465. //
  1466. // Store the original and new data in the buffers.
  1467. // Note that operations are performed differently based on the data type.
  1468. //
  1469. if (pKeyData->pOriginalData) {
  1470. switch (pKeyData->dwOriginalValueType) {
  1471. case REG_DWORD:
  1472. wsprintf(g_pwszOriginalData, L"%lu", (*(DWORD*)pKeyData->pOriginalData));
  1473. break;
  1474. case REG_SZ:
  1475. case REG_EXPAND_SZ:
  1476. wcscpy(g_pwszOriginalData, (const WCHAR*)pKeyData->pOriginalData);
  1477. break;
  1478. case REG_MULTI_SZ:
  1479. ExtractMultiSzStrings(pKeyData->pOriginalData,
  1480. &g_pwszOriginalData);
  1481. break;
  1482. case REG_BINARY:
  1483. ExtractBinaryData(pKeyData->pOriginalData,
  1484. pKeyData->cbOriginalDataSize,
  1485. &g_pwszOriginalData);
  1486. break;
  1487. default:
  1488. DPFN(eDbgLevelError, "[FormatValueData] Unsupported value type");
  1489. break;
  1490. }
  1491. }
  1492. if (pKeyData->pFinalData) {
  1493. switch (pKeyData->dwFinalValueType) {
  1494. case REG_DWORD:
  1495. wsprintf(g_pwszFinalData, L"%lu", (*(DWORD*)pKeyData->pFinalData));
  1496. break;
  1497. case REG_SZ:
  1498. case REG_EXPAND_SZ:
  1499. wcscpy(g_pwszFinalData, (const WCHAR*)pKeyData->pFinalData);
  1500. break;
  1501. case REG_MULTI_SZ:
  1502. ExtractMultiSzStrings(pKeyData->pFinalData,
  1503. &g_pwszFinalData);
  1504. break;
  1505. case REG_BINARY:
  1506. ExtractBinaryData(pKeyData->pFinalData,
  1507. pKeyData->cbFinalDataSize,
  1508. &g_pwszFinalData);
  1509. break;
  1510. default:
  1511. DPFN(eDbgLevelError, "[FormatValueData] Unsupported value type");
  1512. break;
  1513. }
  1514. }
  1515. //
  1516. // Ensure that our unique id doesn't show up in the log.
  1517. //
  1518. if (_wcsicmp(pKeyData->wszValueName, g_wszUniqueId)) {
  1519. pwszValueName = pKeyData->wszValueName;
  1520. }
  1521. //
  1522. // Put the data into an XML element and log it.
  1523. //
  1524. FormatValueDataIntoElement(csFullKeyPath,
  1525. pwszOperation,
  1526. pwszValueName,
  1527. wszOriginalValueType,
  1528. wszFinalValueType);
  1529. }
  1530. /*++
  1531. Determines the changes that took place on the specified key and
  1532. if applicable, writes it to the log.
  1533. --*/
  1534. BOOL
  1535. EvaluateKeyChanges(
  1536. IN PLOG_OPEN_KEY pLogOpenKey
  1537. )
  1538. {
  1539. if (!pLogOpenKey) {
  1540. DPFN(eDbgLevelError, "[EvaluateKeyChanges] Invalid parameter");
  1541. return FALSE;
  1542. }
  1543. //
  1544. // 1. Check for deletion of an existing key.
  1545. //
  1546. if ((pLogOpenKey->dwFlags & LRC_DELETED_KEY) &&
  1547. (pLogOpenKey->dwFlags & LRC_EXISTING_KEY)) {
  1548. FormatKeyDataIntoElement(L"Deleted Key", pLogOpenKey);
  1549. return TRUE;
  1550. }
  1551. //
  1552. // 2. Check for creation of a new key.
  1553. //
  1554. if (!(pLogOpenKey->dwFlags & LRC_EXISTING_KEY) &&
  1555. (!(pLogOpenKey->dwFlags & LRC_DELETED_KEY))) {
  1556. FormatKeyDataIntoElement(L"Created Key", pLogOpenKey);
  1557. return TRUE;
  1558. }
  1559. //
  1560. // 3. Check for deletion of a non-existing key.
  1561. // This is an indicator that we should not look for
  1562. // changes to values below this key.
  1563. //
  1564. if (pLogOpenKey->dwFlags & LRC_DELETED_KEY) {
  1565. return FALSE;
  1566. }
  1567. return TRUE;
  1568. }
  1569. /*++
  1570. Determines the changes that took place on the specified value and
  1571. if applicable, writes it to the log.
  1572. --*/
  1573. void
  1574. EvaluateValueChanges(
  1575. IN PKEY_DATA pKeyData,
  1576. IN PLOG_OPEN_KEY pLogOpenKey
  1577. )
  1578. {
  1579. if (!pKeyData || !pLogOpenKey) {
  1580. DPFN(eDbgLevelError, "[EvaluateValueChanges] Invalid parameter(s)");
  1581. return;
  1582. }
  1583. //
  1584. // 1. Check for deletion of an existing value.
  1585. //
  1586. if ((pKeyData->dwFlags & LRC_DELETED_VALUE) &&
  1587. (pKeyData->dwFlags & LRC_EXISTING_VALUE)) {
  1588. FormatValueData(L"Deleted Value", pKeyData, pLogOpenKey);
  1589. return;
  1590. }
  1591. //
  1592. // 2. Check for modification of an existing value.
  1593. //
  1594. if ((pKeyData->dwFlags & LRC_EXISTING_VALUE) &&
  1595. (pKeyData->dwFlags & LRC_MODIFIED_VALUE)) {
  1596. FormatValueData(L"Modified Value", pKeyData, pLogOpenKey);
  1597. return;
  1598. }
  1599. //
  1600. // 3. Check for creation of a new value value.
  1601. //
  1602. if ((pKeyData->dwFlags & LRC_MODIFIED_VALUE) &&
  1603. (!(pKeyData->dwFlags & LRC_DELETED_VALUE) &&
  1604. (!(pKeyData->dwFlags & LRC_EXISTING_VALUE)))) {
  1605. FormatValueData(L"Created Value", pKeyData, pLogOpenKey);
  1606. return;
  1607. }
  1608. }
  1609. /*++
  1610. Write the entire linked list out to the log file.
  1611. --*/
  1612. BOOL
  1613. WriteListToLogFile(
  1614. void
  1615. )
  1616. {
  1617. PLIST_ENTRY pKeyNext = NULL;
  1618. PLIST_ENTRY pValueHead = NULL;
  1619. PLIST_ENTRY pValueNext = NULL;
  1620. PKEY_DATA pKeyData = NULL;
  1621. PLOG_OPEN_KEY pOpenKey = NULL;
  1622. //
  1623. // Write out modifications for keys.
  1624. //
  1625. pKeyNext = g_OpenKeyListHead.Blink;
  1626. while (pKeyNext != &g_OpenKeyListHead) {
  1627. pOpenKey = CONTAINING_RECORD(pKeyNext, LOG_OPEN_KEY, Entry);
  1628. //
  1629. // EvaluateKeyChanges will return TRUE if the key was not
  1630. // deleted. If this is the case, continue the search and
  1631. // evaluate changes to values within this key.
  1632. //
  1633. if (EvaluateKeyChanges(pOpenKey)) {
  1634. //
  1635. // Write out modifications for values.
  1636. //
  1637. pValueHead = &pOpenKey->KeyData;
  1638. pValueNext = pValueHead->Blink;
  1639. while (pValueNext != pValueHead) {
  1640. pKeyData = CONTAINING_RECORD(pValueNext, KEY_DATA, Entry);
  1641. EvaluateValueChanges(pKeyData, pOpenKey);
  1642. pValueNext = pValueNext->Blink;
  1643. }
  1644. }
  1645. pKeyNext = pKeyNext->Blink;
  1646. }
  1647. CloseLogFile();
  1648. return TRUE;
  1649. }
  1650. //
  1651. // Begin implementation of the class.
  1652. //
  1653. LONG
  1654. CLogRegistry::CreateKeyExA(
  1655. HKEY hKey,
  1656. LPCSTR pszSubKey,
  1657. DWORD Reserved,
  1658. LPSTR pszClass,
  1659. DWORD dwOptions,
  1660. REGSAM samDesired,
  1661. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  1662. PHKEY phkResult,
  1663. LPDWORD lpdwDisposition
  1664. )
  1665. {
  1666. LPWSTR pwszSubKey = NULL;
  1667. LPWSTR pwszClass = NULL;
  1668. LONG lRetVal;
  1669. //
  1670. // Stub out to CreateKeyExW.
  1671. //
  1672. if (pszSubKey) {
  1673. if (!ConvertAnsiToUnicode(pszSubKey, &pwszSubKey)) {
  1674. DPFN(eDbgLevelError, "[CreateKeyExA] Ansi -> Unicode failed");
  1675. return ERROR_OUTOFMEMORY;
  1676. }
  1677. }
  1678. if (pszClass) {
  1679. if (!ConvertAnsiToUnicode(pszClass, &pwszClass)) {
  1680. DPFN(eDbgLevelError, "[CreateKeyExA] Ansi to Unicode failed");
  1681. return ERROR_OUTOFMEMORY;
  1682. }
  1683. }
  1684. lRetVal = CreateKeyExW(
  1685. hKey,
  1686. pwszSubKey,
  1687. Reserved,
  1688. pwszClass,
  1689. dwOptions,
  1690. samDesired,
  1691. lpSecurityAttributes,
  1692. phkResult,
  1693. lpdwDisposition);
  1694. if (pwszSubKey) {
  1695. MemFree(pwszSubKey);
  1696. }
  1697. if (pwszClass) {
  1698. MemFree(pwszClass);
  1699. }
  1700. return lRetVal;
  1701. }
  1702. LONG
  1703. CLogRegistry::CreateKeyExW(
  1704. HKEY hKey,
  1705. LPCWSTR pwszSubKey,
  1706. DWORD Reserved,
  1707. LPWSTR pwszClass,
  1708. DWORD dwOptions,
  1709. REGSAM samDesired,
  1710. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  1711. PHKEY phkResult,
  1712. LPDWORD lpdwDisposition
  1713. )
  1714. {
  1715. DWORD dwDisposition = 0;
  1716. LONG lRetVal;
  1717. BOOL fExisting = FALSE;
  1718. if (!lpdwDisposition) {
  1719. lpdwDisposition = &dwDisposition;
  1720. }
  1721. lRetVal = ORIGINAL_API(RegCreateKeyExW)(
  1722. hKey,
  1723. pwszSubKey,
  1724. Reserved,
  1725. pwszClass,
  1726. dwOptions,
  1727. samDesired,
  1728. lpSecurityAttributes,
  1729. phkResult,
  1730. lpdwDisposition);
  1731. if (lRetVal == ERROR_SUCCESS) {
  1732. if (REG_OPENED_EXISTING_KEY == *lpdwDisposition) {
  1733. fExisting = TRUE;
  1734. }
  1735. UpdateKeyList(hKey,
  1736. *phkResult,
  1737. pwszSubKey,
  1738. NULL,
  1739. fExisting,
  1740. eAddKeyHandle);
  1741. }
  1742. return lRetVal;
  1743. }
  1744. LONG
  1745. CLogRegistry::OpenKeyExA(
  1746. HKEY hKey,
  1747. LPCSTR pszSubKey,
  1748. DWORD ulOptions,
  1749. REGSAM samDesired,
  1750. PHKEY phkResult
  1751. )
  1752. {
  1753. LPWSTR pwszSubKey = NULL;
  1754. LONG lRetVal;
  1755. //
  1756. // Stub out to OpenKeyExW.
  1757. //
  1758. if (pszSubKey) {
  1759. if (!ConvertAnsiToUnicode(pszSubKey, &pwszSubKey)) {
  1760. DPFN(eDbgLevelError, "[OpenKeyExA] Ansi -> Unicode failed");
  1761. return ERROR_OUTOFMEMORY;
  1762. }
  1763. }
  1764. lRetVal = OpenKeyExW(
  1765. hKey,
  1766. pwszSubKey,
  1767. ulOptions,
  1768. samDesired,
  1769. phkResult);
  1770. if (pwszSubKey) {
  1771. MemFree(pwszSubKey);
  1772. }
  1773. return lRetVal;
  1774. }
  1775. LONG
  1776. CLogRegistry::OpenKeyExW(
  1777. HKEY hKey,
  1778. LPCWSTR pwszSubKey,
  1779. DWORD ulOptions,
  1780. REGSAM samDesired,
  1781. PHKEY phkResult
  1782. )
  1783. {
  1784. LONG lRetVal;
  1785. lRetVal = ORIGINAL_API(RegOpenKeyExW)(
  1786. hKey,
  1787. pwszSubKey,
  1788. ulOptions,
  1789. samDesired,
  1790. phkResult);
  1791. if (lRetVal == ERROR_SUCCESS) {
  1792. UpdateKeyList(hKey,
  1793. *phkResult,
  1794. pwszSubKey,
  1795. NULL,
  1796. TRUE,
  1797. eAddKeyHandle);
  1798. }
  1799. return lRetVal;
  1800. }
  1801. LONG
  1802. CLogRegistry::OpenCurrentUser(
  1803. REGSAM samDesired,
  1804. PHKEY phkResult
  1805. )
  1806. {
  1807. LONG lRetVal;
  1808. lRetVal = ORIGINAL_API(RegOpenCurrentUser)(
  1809. samDesired,
  1810. phkResult);
  1811. if (lRetVal == ERROR_SUCCESS) {
  1812. UpdateKeyList(HKEY_CURRENT_USER,
  1813. *phkResult,
  1814. NULL,
  1815. NULL,
  1816. TRUE,
  1817. eAddKeyHandle);
  1818. }
  1819. return lRetVal;
  1820. }
  1821. LONG
  1822. CLogRegistry::OpenUserClassesRoot(
  1823. HANDLE hToken,
  1824. DWORD dwOptions,
  1825. REGSAM samDesired,
  1826. PHKEY phkResult
  1827. )
  1828. {
  1829. LONG lRetVal;
  1830. lRetVal = ORIGINAL_API(RegOpenUserClassesRoot)(
  1831. hToken,
  1832. dwOptions,
  1833. samDesired,
  1834. phkResult);
  1835. if (lRetVal == ERROR_SUCCESS) {
  1836. UpdateKeyList(HKEY_CLASSES_ROOT,
  1837. *phkResult,
  1838. NULL,
  1839. NULL,
  1840. TRUE,
  1841. eAddKeyHandle);
  1842. }
  1843. return lRetVal;
  1844. }
  1845. LONG
  1846. CLogRegistry::SetValueA(
  1847. HKEY hKey,
  1848. LPCSTR pszSubKey,
  1849. DWORD dwType,
  1850. LPCSTR lpData,
  1851. DWORD cbData
  1852. )
  1853. {
  1854. LPWSTR pwszSubKey = NULL;
  1855. LPWSTR pwszData = NULL;
  1856. LONG lRetVal;
  1857. //
  1858. // Stub out to SetValueW.
  1859. //
  1860. if (pszSubKey) {
  1861. if (!ConvertAnsiToUnicode(pszSubKey, &pwszSubKey)) {
  1862. DPFN(eDbgLevelError, "[SetValueA] Ansi -> Unicode failed");
  1863. return ERROR_OUTOFMEMORY;
  1864. }
  1865. }
  1866. if (lpData) {
  1867. if (!ConvertAnsiToUnicode(lpData, &pwszData)) {
  1868. DPFN(eDbgLevelError, "[SetValueA] Ansi to Unicode failed");
  1869. return ERROR_OUTOFMEMORY;
  1870. }
  1871. }
  1872. lRetVal = SetValueW(
  1873. hKey,
  1874. pwszSubKey,
  1875. dwType,
  1876. pwszData,
  1877. cbData * sizeof(WCHAR));
  1878. if (pwszSubKey) {
  1879. MemFree(pwszSubKey);
  1880. }
  1881. if (pwszData) {
  1882. MemFree(pwszData);
  1883. }
  1884. return lRetVal;
  1885. }
  1886. LONG
  1887. CLogRegistry::SetValueW(
  1888. HKEY hKey,
  1889. LPCWSTR pwszSubKey,
  1890. DWORD dwType,
  1891. LPCWSTR lpData,
  1892. DWORD cbData
  1893. )
  1894. {
  1895. HKEY hKeyLocal;
  1896. LONG lRetVal;
  1897. //
  1898. // Call OpenKeyEx to force this key to be added to the list.
  1899. //
  1900. if (pwszSubKey) {
  1901. lRetVal = OpenKeyExW(hKey,
  1902. pwszSubKey,
  1903. 0,
  1904. KEY_SET_VALUE,
  1905. &hKeyLocal);
  1906. if (ERROR_SUCCESS != lRetVal) {
  1907. DPFN(eDbgLevelError, "[SetValueW] Failed to open key");
  1908. return lRetVal;
  1909. }
  1910. lRetVal = SetValueExW(hKeyLocal,
  1911. NULL,
  1912. 0,
  1913. dwType,
  1914. (const BYTE*)lpData,
  1915. cbData);
  1916. CloseKey(hKeyLocal);
  1917. return lRetVal;
  1918. }
  1919. //
  1920. // All other cases will be handled properly.
  1921. //
  1922. lRetVal = SetValueExW(hKey,
  1923. NULL,
  1924. 0,
  1925. dwType,
  1926. (const BYTE*)lpData,
  1927. cbData);
  1928. return lRetVal;
  1929. }
  1930. LONG
  1931. CLogRegistry::SetValueExA(
  1932. HKEY hKey,
  1933. LPCSTR pszValueName,
  1934. DWORD Reserved,
  1935. DWORD dwType,
  1936. CONST BYTE* lpData,
  1937. DWORD cbData
  1938. )
  1939. {
  1940. LPWSTR pwszData = NULL;
  1941. LPWSTR pwszValueName = NULL;
  1942. LONG lRetVal;
  1943. BOOL fString = FALSE;
  1944. //
  1945. // Stub out to SetValueExW.
  1946. //
  1947. if (pszValueName) {
  1948. if (!ConvertAnsiToUnicode(pszValueName, &pwszValueName)) {
  1949. DPFN(eDbgLevelError, "[SetValueExA] Ansi -> Unicode failed");
  1950. return ERROR_OUTOFMEMORY;
  1951. }
  1952. }
  1953. if (REG_SZ == dwType || REG_EXPAND_SZ == dwType || REG_MULTI_SZ == dwType) {
  1954. fString = TRUE;
  1955. }
  1956. //
  1957. // If the data is of type string, convert it to Unicode.
  1958. //
  1959. if (lpData) {
  1960. if (REG_MULTI_SZ == dwType) {
  1961. if (!ConvertMultiSzToUnicode((LPCSTR)lpData, &pwszData)) {
  1962. DPFN(eDbgLevelError, "[SetValueExA] Multi Sz to Unicode failed");
  1963. return ERROR_OUTOFMEMORY;
  1964. }
  1965. }
  1966. else if (REG_SZ == dwType || REG_EXPAND_SZ == dwType) {
  1967. if (!ConvertAnsiToUnicode((LPCSTR)lpData, &pwszData)) {
  1968. DPFN(eDbgLevelError, "[SetValueExA] Ansi to Unicode failed");
  1969. return ERROR_OUTOFMEMORY;
  1970. }
  1971. }
  1972. }
  1973. if (fString) {
  1974. lRetVal = SetValueExW(
  1975. hKey,
  1976. pwszValueName,
  1977. Reserved,
  1978. dwType,
  1979. (const BYTE*)pwszData,
  1980. cbData * sizeof(WCHAR));
  1981. } else {
  1982. lRetVal = SetValueExW(
  1983. hKey,
  1984. pwszValueName,
  1985. Reserved,
  1986. dwType,
  1987. lpData,
  1988. cbData);
  1989. }
  1990. if (pwszValueName) {
  1991. MemFree(pwszValueName);
  1992. }
  1993. if (pwszData) {
  1994. MemFree(pwszData);
  1995. }
  1996. return lRetVal;
  1997. }
  1998. LONG
  1999. CLogRegistry::SetValueExW(
  2000. HKEY hKey,
  2001. LPCWSTR pwszValueName,
  2002. DWORD Reserved,
  2003. DWORD dwType,
  2004. CONST BYTE* lpData,
  2005. DWORD cbData
  2006. )
  2007. {
  2008. LONG lRetVal;
  2009. UpdateKeyList(NULL, hKey, NULL, pwszValueName, FALSE, eStartModifyValue);
  2010. lRetVal = ORIGINAL_API(RegSetValueExW)(
  2011. hKey,
  2012. pwszValueName,
  2013. Reserved,
  2014. dwType,
  2015. lpData,
  2016. cbData);
  2017. if (ERROR_SUCCESS == lRetVal) {
  2018. UpdateKeyList(NULL, hKey, NULL, pwszValueName, FALSE, eEndModifyValue);
  2019. }
  2020. return lRetVal;
  2021. }
  2022. LONG
  2023. CLogRegistry::CloseKey(
  2024. HKEY hKey
  2025. )
  2026. {
  2027. UpdateKeyList(NULL, hKey, NULL, NULL, TRUE, eRemoveKeyHandle);
  2028. return ORIGINAL_API(RegCloseKey)(hKey);
  2029. }
  2030. LONG
  2031. CLogRegistry::DeleteKeyA(
  2032. HKEY hKey,
  2033. LPCSTR pszSubKey
  2034. )
  2035. {
  2036. LPWSTR pwszSubKey = NULL;
  2037. LONG lRetVal;
  2038. //
  2039. // Stub out to DeleteKeyW.
  2040. //
  2041. if (pszSubKey) {
  2042. if (!ConvertAnsiToUnicode(pszSubKey, &pwszSubKey)) {
  2043. DPFN(eDbgLevelError, "[DeleteKeyA] Ansi -> Unicode failed");
  2044. return ERROR_OUTOFMEMORY;
  2045. }
  2046. }
  2047. lRetVal = DeleteKeyW(hKey, pwszSubKey);
  2048. if (pwszSubKey) {
  2049. MemFree(pwszSubKey);
  2050. }
  2051. return lRetVal;
  2052. }
  2053. LONG
  2054. CLogRegistry::DeleteKeyW(
  2055. HKEY hKey,
  2056. LPCWSTR pwszSubKey
  2057. )
  2058. {
  2059. LONG lRetVal;
  2060. HKEY hKeyLocal;
  2061. //
  2062. // The caller can pass a predefined handle or an open key
  2063. // handle. In all cases, we open the key they're passing
  2064. // to force it into the list. Note that we mainly do
  2065. // this for logging purposes only.
  2066. //
  2067. hKeyLocal = ForceSubKeyIntoList(hKey, pwszSubKey);
  2068. lRetVal = ORIGINAL_API(RegDeleteKeyW)(hKey, pwszSubKey);
  2069. if (ERROR_SUCCESS == lRetVal && hKeyLocal) {
  2070. UpdateKeyList(NULL, hKeyLocal, pwszSubKey, NULL, TRUE, eDeletedKey);
  2071. }
  2072. if (hKeyLocal) {
  2073. CloseKey(hKeyLocal);
  2074. }
  2075. return lRetVal;
  2076. }
  2077. LONG
  2078. CLogRegistry::DeleteValueA(
  2079. HKEY hKey,
  2080. LPCSTR pszValueName
  2081. )
  2082. {
  2083. LPWSTR pwszValueName = NULL;
  2084. LONG lRetVal;
  2085. //
  2086. // Stub out to DeleteValueW.
  2087. //
  2088. if (pszValueName) {
  2089. if (!ConvertAnsiToUnicode(pszValueName, &pwszValueName)) {
  2090. DPFN(eDbgLevelError, "[DeleteValueA] Ansi -> Unicode failed");
  2091. return ERROR_OUTOFMEMORY;
  2092. }
  2093. }
  2094. lRetVal = DeleteValueW(hKey, pwszValueName);
  2095. if (pwszValueName) {
  2096. MemFree(pwszValueName);
  2097. }
  2098. return lRetVal;
  2099. }
  2100. LONG
  2101. CLogRegistry::DeleteValueW(
  2102. HKEY hKey,
  2103. LPCWSTR pwszValueName
  2104. )
  2105. {
  2106. LONG lRetVal;
  2107. UpdateKeyList(NULL, hKey, NULL, pwszValueName, TRUE, eStartDeleteValue);
  2108. lRetVal = ORIGINAL_API(RegDeleteValueW)(hKey, pwszValueName);
  2109. if (ERROR_SUCCESS == lRetVal) {
  2110. UpdateKeyList(NULL, hKey, NULL, pwszValueName, TRUE, eEndDeleteValue);
  2111. }
  2112. return lRetVal;
  2113. }
  2114. CLogRegistry clr;
  2115. //
  2116. // Implemenation of the actual Registry API hooks.
  2117. //
  2118. LONG
  2119. APIHOOK(RegOpenKeyA)(
  2120. HKEY hKey,
  2121. LPSTR lpSubKey,
  2122. PHKEY phkResult
  2123. )
  2124. {
  2125. CLock cLock;
  2126. return clr.OpenKeyExA(
  2127. hKey,
  2128. lpSubKey,
  2129. 0,
  2130. MAXIMUM_ALLOWED,
  2131. phkResult);
  2132. }
  2133. LONG
  2134. APIHOOK(RegOpenKeyW)(
  2135. HKEY hKey,
  2136. LPWSTR lpSubKey,
  2137. PHKEY phkResult
  2138. )
  2139. {
  2140. CLock cLock;
  2141. return clr.OpenKeyExW(
  2142. hKey,
  2143. lpSubKey,
  2144. 0,
  2145. MAXIMUM_ALLOWED,
  2146. phkResult);
  2147. }
  2148. LONG
  2149. APIHOOK(RegOpenKeyExA)(
  2150. HKEY hKey,
  2151. LPCSTR lpSubKey,
  2152. DWORD ulOptions,
  2153. REGSAM samDesired,
  2154. PHKEY phkResult
  2155. )
  2156. {
  2157. CLock cLock;
  2158. return clr.OpenKeyExA(
  2159. hKey,
  2160. lpSubKey,
  2161. ulOptions,
  2162. samDesired,
  2163. phkResult);
  2164. }
  2165. LONG
  2166. APIHOOK(RegOpenKeyExW)(
  2167. HKEY hKey,
  2168. LPCWSTR lpSubKey,
  2169. DWORD ulOptions,
  2170. REGSAM samDesired,
  2171. PHKEY phkResult
  2172. )
  2173. {
  2174. CLock cLock;
  2175. return clr.OpenKeyExW(
  2176. hKey,
  2177. lpSubKey,
  2178. ulOptions,
  2179. samDesired,
  2180. phkResult);
  2181. }
  2182. LONG
  2183. APIHOOK(RegOpenCurrentUser)(
  2184. REGSAM samDesired,
  2185. PHKEY phkResult
  2186. )
  2187. {
  2188. CLock cLock;
  2189. return clr.OpenCurrentUser(
  2190. samDesired,
  2191. phkResult);
  2192. }
  2193. LONG
  2194. APIHOOK(RegOpenUserClassesRoot)(
  2195. HANDLE hToken,
  2196. DWORD dwOptions,
  2197. REGSAM samDesired,
  2198. PHKEY phkResult
  2199. )
  2200. {
  2201. CLock cLock;
  2202. return clr.OpenUserClassesRoot(
  2203. hToken,
  2204. dwOptions,
  2205. samDesired,
  2206. phkResult);
  2207. }
  2208. LONG
  2209. APIHOOK(RegCreateKeyA)(
  2210. HKEY hKey,
  2211. LPCSTR lpSubKey,
  2212. PHKEY phkResult
  2213. )
  2214. {
  2215. CLock cLock;
  2216. return clr.CreateKeyExA(
  2217. hKey,
  2218. lpSubKey,
  2219. 0,
  2220. NULL,
  2221. REG_OPTION_NON_VOLATILE,
  2222. MAXIMUM_ALLOWED,
  2223. NULL,
  2224. phkResult,
  2225. NULL);
  2226. }
  2227. LONG
  2228. APIHOOK(RegCreateKeyW)(
  2229. HKEY hKey,
  2230. LPCWSTR lpSubKey,
  2231. PHKEY phkResult
  2232. )
  2233. {
  2234. CLock cLock;
  2235. return clr.CreateKeyExW(
  2236. hKey,
  2237. lpSubKey,
  2238. 0,
  2239. NULL,
  2240. REG_OPTION_NON_VOLATILE,
  2241. MAXIMUM_ALLOWED,
  2242. NULL,
  2243. phkResult,
  2244. NULL);
  2245. }
  2246. LONG
  2247. APIHOOK(RegCreateKeyExA)(
  2248. HKEY hKey,
  2249. LPCSTR lpSubKey,
  2250. DWORD Reserved,
  2251. LPSTR lpClass,
  2252. DWORD dwOptions,
  2253. REGSAM samDesired,
  2254. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  2255. PHKEY phkResult,
  2256. LPDWORD lpdwDisposition
  2257. )
  2258. {
  2259. CLock cLock;
  2260. return clr.CreateKeyExA(
  2261. hKey,
  2262. lpSubKey,
  2263. Reserved,
  2264. lpClass,
  2265. dwOptions,
  2266. samDesired,
  2267. lpSecurityAttributes,
  2268. phkResult,
  2269. lpdwDisposition);
  2270. }
  2271. LONG
  2272. APIHOOK(RegCreateKeyExW)(
  2273. HKEY hKey,
  2274. LPCWSTR lpSubKey,
  2275. DWORD Reserved,
  2276. LPWSTR lpClass,
  2277. DWORD dwOptions,
  2278. REGSAM samDesired,
  2279. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  2280. PHKEY phkResult,
  2281. LPDWORD lpdwDisposition
  2282. )
  2283. {
  2284. CLock cLock;
  2285. return clr.CreateKeyExW(
  2286. hKey,
  2287. lpSubKey,
  2288. Reserved,
  2289. lpClass,
  2290. dwOptions,
  2291. samDesired,
  2292. lpSecurityAttributes,
  2293. phkResult,
  2294. lpdwDisposition);
  2295. }
  2296. LONG
  2297. APIHOOK(RegSetValueA)(
  2298. HKEY hKey,
  2299. LPCSTR lpSubKey,
  2300. DWORD dwType,
  2301. LPCSTR lpData,
  2302. DWORD cbData
  2303. )
  2304. {
  2305. CLock cLock;
  2306. return clr.SetValueA(
  2307. hKey,
  2308. lpSubKey,
  2309. dwType,
  2310. lpData,
  2311. cbData);
  2312. }
  2313. LONG
  2314. APIHOOK(RegSetValueW)(
  2315. HKEY hKey,
  2316. LPCWSTR lpSubKey,
  2317. DWORD dwType,
  2318. LPCWSTR lpData,
  2319. DWORD cbData
  2320. )
  2321. {
  2322. CLock cLock;
  2323. return clr.SetValueW(
  2324. hKey,
  2325. lpSubKey,
  2326. dwType,
  2327. lpData,
  2328. cbData);
  2329. }
  2330. LONG
  2331. APIHOOK(RegSetValueExA)(
  2332. HKEY hKey,
  2333. LPCSTR lpSubKey,
  2334. DWORD Reserved,
  2335. DWORD dwType,
  2336. CONST BYTE* lpData,
  2337. DWORD cbData
  2338. )
  2339. {
  2340. CLock cLock;
  2341. return clr.SetValueExA(
  2342. hKey,
  2343. lpSubKey,
  2344. Reserved,
  2345. dwType,
  2346. lpData,
  2347. cbData);
  2348. }
  2349. LONG
  2350. APIHOOK(RegSetValueExW)(
  2351. HKEY hKey,
  2352. LPCWSTR lpSubKey,
  2353. DWORD Reserved,
  2354. DWORD dwType,
  2355. CONST BYTE* lpData,
  2356. DWORD cbData
  2357. )
  2358. {
  2359. CLock cLock;
  2360. return clr.SetValueExW(
  2361. hKey,
  2362. lpSubKey,
  2363. Reserved,
  2364. dwType,
  2365. lpData,
  2366. cbData);
  2367. }
  2368. LONG
  2369. APIHOOK(RegCloseKey)(
  2370. HKEY hKey
  2371. )
  2372. {
  2373. CLock cLock;
  2374. return clr.CloseKey(
  2375. hKey);
  2376. }
  2377. LONG
  2378. APIHOOK(RegDeleteKeyA)(
  2379. HKEY hKey,
  2380. LPCSTR lpSubKey
  2381. )
  2382. {
  2383. CLock cLock;
  2384. return clr.DeleteKeyA(
  2385. hKey,
  2386. lpSubKey);
  2387. }
  2388. LONG
  2389. APIHOOK(RegDeleteKeyW)(
  2390. HKEY hKey,
  2391. LPCWSTR lpSubKey
  2392. )
  2393. {
  2394. CLock cLock;
  2395. return clr.DeleteKeyW(
  2396. hKey,
  2397. lpSubKey);
  2398. }
  2399. LONG
  2400. APIHOOK(RegDeleteValueA)(
  2401. HKEY hKey,
  2402. LPCSTR lpValueName
  2403. )
  2404. {
  2405. CLock cLock;
  2406. return clr.DeleteValueA(
  2407. hKey,
  2408. lpValueName);
  2409. }
  2410. LONG
  2411. APIHOOK(RegDeleteValueW)(
  2412. HKEY hKey,
  2413. LPCWSTR lpValueName
  2414. )
  2415. {
  2416. CLock cLock;
  2417. return clr.DeleteValueW(
  2418. hKey,
  2419. lpValueName);
  2420. }
  2421. /*++
  2422. Creates a unique id used to represent NULL values on registry calls.
  2423. --*/
  2424. void
  2425. InitializeNullValueId(
  2426. void
  2427. )
  2428. {
  2429. SYSTEMTIME st;
  2430. WCHAR* pwszSlash = NULL;
  2431. WCHAR wszModPathName[MAX_PATH];
  2432. WCHAR wszShortName[MAX_PATH];
  2433. //
  2434. // Because there is a NULL valuename for every key in the registry,
  2435. // we need a unique key that we can use to represent NULL in our list.
  2436. //
  2437. if (!GetModuleFileName(NULL, wszModPathName, ARRAYSIZE(wszModPathName))) {
  2438. wcscpy(wszModPathName, L"uniqueexeidentifier");
  2439. }
  2440. pwszSlash = wcsrchr(wszModPathName, '\\');
  2441. if (pwszSlash) {
  2442. wcsncpy(wszShortName, ++pwszSlash, (wcslen(pwszSlash)+1));
  2443. }
  2444. GetLocalTime(&st);
  2445. //
  2446. // The format of our unique id will look like this:
  2447. // processname.xxx-lrc-yymmdd-default
  2448. //
  2449. wsprintf(g_wszUniqueId,
  2450. L"%ls-lrc-%02hu%02hu%02hu-default",
  2451. wszShortName,
  2452. st.wYear,
  2453. st.wMonth,
  2454. st.wDay);
  2455. }
  2456. /*++
  2457. Adds the predefined key handles to the list.
  2458. --*/
  2459. BOOL
  2460. AddPredefinedHandlesToList(
  2461. void
  2462. )
  2463. {
  2464. UINT uCount;
  2465. PLOG_OPEN_KEY pKey = NULL;
  2466. HKEY rgKeys[NUM_PREDEFINED_HANDLES] = { HKEY_LOCAL_MACHINE,
  2467. HKEY_CLASSES_ROOT,
  2468. HKEY_CURRENT_USER,
  2469. HKEY_USERS,
  2470. HKEY_CURRENT_CONFIG,
  2471. HKEY_DYN_DATA,
  2472. HKEY_PERFORMANCE_DATA };
  2473. for (uCount = 0; uCount < NUM_PREDEFINED_HANDLES; uCount++) {
  2474. pKey = (PLOG_OPEN_KEY)MemAlloc(sizeof(LOG_OPEN_KEY));
  2475. if (!pKey) {
  2476. DPFN(eDbgLevelError,
  2477. "[AddPredefinedHandlesToList] No memory available");
  2478. return FALSE;
  2479. }
  2480. pKey->pwszFullKeyPath = (LPWSTR)MemAlloc(MAX_ROOT_LENGTH * sizeof(WCHAR));
  2481. if (!pKey->pwszFullKeyPath) {
  2482. DPFN(eDbgLevelError,
  2483. "[AddPredefinedHandlesToList] Failed to allocate memory");
  2484. return FALSE;
  2485. }
  2486. if (!PredefinedKeyToString(rgKeys[uCount], &pKey->pwszFullKeyPath)) {
  2487. DPFN(eDbgLevelError,
  2488. "[AddPredefinedHandlesToList] PredefinedKey -> String failed");
  2489. return FALSE;
  2490. }
  2491. pKey->hKeyRoot = rgKeys[uCount];
  2492. pKey->hKeyBase[0] = rgKeys[uCount];
  2493. pKey->pwszSubKeyPath = NULL;
  2494. pKey->dwFlags = LRC_EXISTING_KEY;
  2495. pKey->cHandles = 1;
  2496. InitializeListHead(&pKey->KeyData);
  2497. InsertHeadList(&g_OpenKeyListHead, &pKey->Entry);
  2498. }
  2499. return TRUE;
  2500. }
  2501. /*++
  2502. Initialize the the list head and the log file.
  2503. --*/
  2504. BOOL
  2505. InitializeShim(
  2506. void
  2507. )
  2508. {
  2509. CLock cLock;
  2510. //
  2511. // Initialize our open key handle list head and the
  2512. // key data list head.
  2513. //
  2514. InitializeListHead(&g_OpenKeyListHead);
  2515. //
  2516. // Add the predefined handles to the list.
  2517. //
  2518. if (!AddPredefinedHandlesToList()) {
  2519. return FALSE;
  2520. }
  2521. InitializeNullValueId();
  2522. //
  2523. // Initialize our log file.
  2524. //
  2525. return InitializeLogFile();
  2526. }
  2527. /*++
  2528. Handle process attach notification.
  2529. --*/
  2530. BOOL
  2531. NOTIFY_FUNCTION(
  2532. DWORD fdwReason
  2533. )
  2534. {
  2535. if (fdwReason == DLL_PROCESS_ATTACH) {
  2536. return InitializeShim();
  2537. } else if (fdwReason == DLL_PROCESS_DETACH) {
  2538. return WriteListToLogFile();
  2539. }
  2540. return TRUE;
  2541. }
  2542. SHIM_INFO_BEGIN()
  2543. SHIM_INFO_DESCRIPTION(AVS_LOGREGCHANGES_DESC)
  2544. SHIM_INFO_FRIENDLY_NAME(AVS_LOGREGCHANGES_FRIENDLY)
  2545. SHIM_INFO_VERSION(1, 5)
  2546. SHIM_INFO_FLAGS(AVRF_FLAG_NO_DEFAULT)
  2547. SHIM_INFO_END()
  2548. /*++
  2549. Register hooked functions.
  2550. --*/
  2551. HOOK_BEGIN
  2552. CALL_NOTIFY_FUNCTION
  2553. DUMP_VERIFIER_LOG_ENTRY(VLOG_LOGREGCHANGES_LOGLOC,
  2554. AVS_LOGREGCHANGES_LOGLOC,
  2555. AVS_LOGREGCHANGES_LOGLOC_R,
  2556. AVS_LOGREGCHANGES_LOGLOC_URL)
  2557. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA)
  2558. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyW)
  2559. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA)
  2560. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExW)
  2561. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenCurrentUser)
  2562. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenUserClassesRoot)
  2563. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyA)
  2564. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyW)
  2565. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExA)
  2566. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExW)
  2567. APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueA)
  2568. APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueW)
  2569. APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueExA)
  2570. APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueExW)
  2571. APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteKeyA)
  2572. APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteKeyW)
  2573. APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteValueA)
  2574. APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteValueW)
  2575. APIHOOK_ENTRY(ADVAPI32.DLL, RegCloseKey)
  2576. HOOK_END
  2577. IMPLEMENT_SHIM_END