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.

3311 lines
84 KiB

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