2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ps/apphelp.c
5 * PURPOSE: SHIM engine caching.
6 * This caching speeds up checks for the apphelp compatibility layer.
7 * PROGRAMMERS: Mark Jansen
12 https://github.com/mandiant/ShimCacheParser/blob/master/ShimCacheParser.py
13 http://technet.microsoft.com/en-us/library/dd837644(v=ws.10).aspx
14 http://msdn.microsoft.com/en-us/library/bb432182(v=vs.85).aspx
15 http://www.alex-ionescu.com/?p=43
16 http://recxltd.blogspot.nl/2012/04/windows-appcompat-research-notes-part-1.html
17 http://journeyintoir.blogspot.ch/2013/12/revealing-recentfilecachebcf-file.html
18 https://dl.mandiant.com/EE/library/Whitepaper_ShimCacheParser.pdf
21 /* INCLUDES ******************************************************************/
27 /* GLOBALS *******************************************************************/
29 static BOOLEAN ApphelpCacheEnabled
= FALSE
;
30 static ERESOURCE ApphelpCacheLock
;
31 static RTL_AVL_TABLE ApphelpShimCache
;
32 static LIST_ENTRY ApphelpShimCacheAge
;
34 extern ULONG InitSafeBootMode
;
36 static UNICODE_STRING AppCompatCacheKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatCache");
37 static OBJECT_ATTRIBUTES AppCompatKeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatCacheKey
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
);
38 static UNICODE_STRING AppCompatCacheValue
= RTL_CONSTANT_STRING(L
"AppCompatCache");
40 #define EMPTY_SHIM_ENTRY { { 0 }, { { 0 } }, 0 }
41 #define MAX_SHIM_ENTRIES 0x200
42 #define TAG_SHIM 'MIHS'
44 #ifndef INVALID_HANDLE_VALUE
45 #define INVALID_HANDLE_VALUE (HANDLE)(-1)
50 typedef struct SHIM_PERSISTENT_CACHE_HEADER_52
54 } SHIM_PERSISTENT_CACHE_HEADER_52
, *PSHIM_PERSISTENT_CACHE_HEADER_52
;
56 /* The data that is present in the registry (Win2k3 version) */
57 typedef struct SHIM_PERSISTENT_CACHE_ENTRY_52
59 UNICODE_STRING ImageName
;
60 LARGE_INTEGER DateTime
;
61 LARGE_INTEGER FileSize
;
62 } SHIM_PERSISTENT_CACHE_ENTRY_52
, *PSHIM_PERSISTENT_CACHE_ENTRY_52
;
66 #define CACHE_MAGIC_NT_52 0xbadc0ffe
67 #define CACHE_HEADER_SIZE_NT_52 0x8
68 #define NT52_PERSISTENT_ENTRY_SIZE32 0x18
69 #define NT52_PERSISTENT_ENTRY_SIZE64 0x20
71 //#define CACHE_MAGIC_NT_61 0xbadc0fee
72 //#define CACHE_HEADER_SIZE_NT_61 0x80
73 //#define NT61_PERSISTENT_ENTRY_SIZE32 0x20
74 //#define NT61_PERSISTENT_ENTRY_SIZE64 0x30
76 #define SHIM_CACHE_MAGIC CACHE_MAGIC_NT_52
77 #define SHIM_CACHE_HEADER_SIZE CACHE_HEADER_SIZE_NT_52
79 #define SHIM_PERSISTENT_CACHE_ENTRY_SIZE NT52_PERSISTENT_ENTRY_SIZE64
81 #define SHIM_PERSISTENT_CACHE_ENTRY_SIZE NT52_PERSISTENT_ENTRY_SIZE32
83 #define SHIM_PERSISTENT_CACHE_HEADER SHIM_PERSISTENT_CACHE_HEADER_52
84 #define PSHIM_PERSISTENT_CACHE_HEADER PSHIM_PERSISTENT_CACHE_HEADER_52
85 #define SHIM_PERSISTENT_CACHE_ENTRY SHIM_PERSISTENT_CACHE_ENTRY_52
86 #define PSHIM_PERSISTENT_CACHE_ENTRY PSHIM_PERSISTENT_CACHE_ENTRY_52
88 C_ASSERT(sizeof(SHIM_PERSISTENT_CACHE_ENTRY
) == SHIM_PERSISTENT_CACHE_ENTRY_SIZE
);
89 C_ASSERT(sizeof(SHIM_PERSISTENT_CACHE_HEADER
) == SHIM_CACHE_HEADER_SIZE
);
91 /* The struct we keep in memory */
92 typedef struct SHIM_CACHE_ENTRY
95 SHIM_PERSISTENT_CACHE_ENTRY Persistent
;
97 } SHIM_CACHE_ENTRY
, *PSHIM_CACHE_ENTRY
;
99 /* PRIVATE FUNCTIONS *********************************************************/
105 return ExAllocatePoolWithTag(PagedPool
, ByteSize
, TAG_SHIM
);
112 ExFreePoolWithTag(Data
, TAG_SHIM
);
116 ApphelpCacheAcquireLock(VOID
)
118 KeEnterCriticalRegion();
119 ExAcquireResourceExclusiveLite(&ApphelpCacheLock
, TRUE
);
123 ApphelpCacheTryAcquireLock(VOID
)
125 KeEnterCriticalRegion();
126 if (!ExTryToAcquireResourceExclusiveLite(&ApphelpCacheLock
))
128 KeLeaveCriticalRegion();
135 ApphelpCacheReleaseLock(VOID
)
137 ExReleaseResourceLite(&ApphelpCacheLock
);
138 KeLeaveCriticalRegion();
142 ApphelpDuplicateUnicodeString(
143 _Out_ PUNICODE_STRING Destination
,
144 _In_ PCUNICODE_STRING Source
)
146 Destination
->Length
= Source
->Length
;
147 if (Destination
->Length
)
149 Destination
->MaximumLength
= Destination
->Length
+ sizeof(WCHAR
);
150 Destination
->Buffer
= ApphelpAlloc(Destination
->MaximumLength
);
151 RtlCopyMemory(Destination
->Buffer
, Source
->Buffer
, Destination
->Length
);
152 Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
156 Destination
->MaximumLength
= 0;
157 Destination
->Buffer
= NULL
;
162 ApphelpFreeUnicodeString(
163 _Inout_ PUNICODE_STRING String
)
167 ApphelpFree(String
->Buffer
);
170 String
->MaximumLength
= 0;
171 String
->Buffer
= NULL
;
174 /* Query file info from a handle, storing it in Entry */
176 ApphelpCacheQueryInfo(
177 _In_ HANDLE ImageHandle
,
178 _Out_ PSHIM_CACHE_ENTRY Entry
)
180 IO_STATUS_BLOCK IoStatusBlock
;
181 FILE_BASIC_INFORMATION FileBasic
;
182 FILE_STANDARD_INFORMATION FileStandard
;
185 Status
= ZwQueryInformationFile(ImageHandle
,
189 FileBasicInformation
);
190 if (!NT_SUCCESS(Status
))
195 Status
= ZwQueryInformationFile(ImageHandle
,
198 sizeof(FileStandard
),
199 FileStandardInformation
);
200 if (NT_SUCCESS(Status
))
202 Entry
->Persistent
.DateTime
= FileBasic
.LastWriteTime
;
203 Entry
->Persistent
.FileSize
= FileStandard
.EndOfFile
;
208 RTL_GENERIC_COMPARE_RESULTS
210 ApphelpShimCacheCompareRoutine(
211 _In_ PRTL_AVL_TABLE Table
,
212 _In_ PVOID FirstStruct
,
213 _In_ PVOID SecondStruct
)
215 PSHIM_CACHE_ENTRY FirstEntry
= FirstStruct
;
216 PSHIM_CACHE_ENTRY SecondEntry
= SecondStruct
;
219 Result
= RtlCompareUnicodeString(&FirstEntry
->Persistent
.ImageName
,
220 &SecondEntry
->Persistent
.ImageName
,
224 return GenericLessThan
;
226 else if (Result
== 0)
230 return GenericGreaterThan
;
235 ApphelpShimCacheAllocateRoutine(
236 _In_ PRTL_AVL_TABLE Table
,
239 return ApphelpAlloc(ByteSize
);
244 ApphelpShimCacheFreeRoutine(
245 _In_ PRTL_AVL_TABLE Table
,
253 _In_reads_(DataLength
) PUCHAR Data
,
254 _In_ ULONG DataLength
)
256 PSHIM_PERSISTENT_CACHE_HEADER Header
= (PSHIM_PERSISTENT_CACHE_HEADER
)Data
;
259 UNICODE_STRING String
;
260 SHIM_CACHE_ENTRY Entry
= EMPTY_SHIM_ENTRY
;
261 PSHIM_CACHE_ENTRY Result
;
262 PSHIM_PERSISTENT_CACHE_ENTRY Persistent
;
264 if (DataLength
< CACHE_HEADER_SIZE_NT_52
)
266 DPRINT1("SHIMS: ApphelpCacheParse not enough data for a minimal header (0x%x)\n", DataLength
);
267 return STATUS_INVALID_PARAMETER
;
270 if (Header
->Magic
!= SHIM_CACHE_MAGIC
)
272 DPRINT1("SHIMS: ApphelpCacheParse found invalid magic (0x%x)\n", Header
->Magic
);
273 return STATUS_INVALID_PARAMETER
;
276 NumEntries
= Header
->NumEntries
;
277 DPRINT("SHIMS: ApphelpCacheParse walking %d entries\n", NumEntries
);
278 for (Cur
= 0; Cur
< NumEntries
; ++Cur
)
280 Persistent
= (PSHIM_PERSISTENT_CACHE_ENTRY
)(Data
+ SHIM_CACHE_HEADER_SIZE
+
281 (Cur
* SHIM_PERSISTENT_CACHE_ENTRY_SIZE
));
282 /* The entry in the Persistent storage is not really a UNICODE_STRING,
283 so we have to convert the offset into a real pointer before using it. */
284 String
.Length
= Persistent
->ImageName
.Length
;
285 String
.MaximumLength
= Persistent
->ImageName
.MaximumLength
;
286 String
.Buffer
= (PWCHAR
)((ULONG_PTR
)Persistent
->ImageName
.Buffer
+ Data
);
288 /* Now we copy all data to a local buffer, that can be safely duplicated by RtlInsert */
289 Entry
.Persistent
= *Persistent
;
290 ApphelpDuplicateUnicodeString(&Entry
.Persistent
.ImageName
, &String
);
291 Result
= RtlInsertElementGenericTableAvl(&ApphelpShimCache
,
297 DPRINT1("SHIMS: ApphelpCacheParse insert failed\n");
298 ApphelpFreeUnicodeString(&Entry
.Persistent
.ImageName
);
299 return STATUS_INVALID_PARAMETER
;
301 InsertTailList(&ApphelpShimCacheAge
, &Result
->List
);
303 return STATUS_SUCCESS
;
307 ApphelpCacheRead(VOID
)
311 KEY_VALUE_PARTIAL_INFORMATION KeyValueObject
;
312 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= &KeyValueObject
;
313 ULONG KeyInfoSize
, ResultSize
;
315 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &AppCompatKeyAttributes
);
316 if (!NT_SUCCESS(Status
))
318 DPRINT1("SHIMS: ApphelpCacheRead could not even open Session Manager\\AppCompatCache (0x%x)\n", Status
);
322 Status
= ZwQueryValueKey(KeyHandle
,
323 &AppCompatCacheValue
,
324 KeyValuePartialInformation
,
326 sizeof(KeyValueObject
),
328 if (Status
== STATUS_BUFFER_OVERFLOW
)
330 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyValueInformation
->DataLength
;
331 KeyValueInformation
= ApphelpAlloc(KeyInfoSize
);
332 if (KeyValueInformation
!= NULL
)
334 Status
= ZwQueryValueKey(KeyHandle
,
335 &AppCompatCacheValue
,
336 KeyValuePartialInformation
,
343 if (NT_SUCCESS(Status
) && KeyValueInformation
->Type
== REG_BINARY
)
345 Status
= ApphelpCacheParse(KeyValueInformation
->Data
,
346 KeyValueInformation
->DataLength
);
350 DPRINT1("SHIMS: ApphelpCacheRead not loaded from registry (0x%x)\n", Status
);
353 if (KeyValueInformation
!= &KeyValueObject
&& KeyValueInformation
!= NULL
)
355 ApphelpFree(KeyValueInformation
);
359 return NT_SUCCESS(Status
);
363 ApphelpCacheWrite(VOID
)
365 ULONG Length
= SHIM_CACHE_HEADER_SIZE
;
366 ULONG NumEntries
= 0;
367 PLIST_ENTRY ListEntry
;
368 PUCHAR Buffer
, BufferNamePos
;
369 PSHIM_PERSISTENT_CACHE_HEADER Header
;
370 PSHIM_PERSISTENT_CACHE_ENTRY WriteEntry
;
374 /* First we have to calculate the required size. */
375 ApphelpCacheAcquireLock();
376 ListEntry
= ApphelpShimCacheAge
.Flink
;
377 while (ListEntry
!= &ApphelpShimCacheAge
)
379 PSHIM_CACHE_ENTRY Entry
= CONTAINING_RECORD(ListEntry
, SHIM_CACHE_ENTRY
, List
);
380 Length
+= SHIM_PERSISTENT_CACHE_ENTRY_SIZE
;
381 Length
+= Entry
->Persistent
.ImageName
.MaximumLength
;
383 ListEntry
= ListEntry
->Flink
;
385 DPRINT("SHIMS: ApphelpCacheWrite, %d Entries, total size: %d\n", NumEntries
, Length
);
386 Length
= ROUND_UP(Length
, sizeof(ULONGLONG
));
387 DPRINT("SHIMS: ApphelpCacheWrite, Rounded to: %d\n", Length
);
389 /* Now we allocate and prepare some helpers */
390 Buffer
= ApphelpAlloc(Length
);
391 BufferNamePos
= Buffer
+ Length
;
392 Header
= (PSHIM_PERSISTENT_CACHE_HEADER
)Buffer
;
393 WriteEntry
= (PSHIM_PERSISTENT_CACHE_ENTRY
)(Buffer
+ SHIM_CACHE_HEADER_SIZE
);
395 Header
->Magic
= SHIM_CACHE_MAGIC
;
396 Header
->NumEntries
= NumEntries
;
398 ListEntry
= ApphelpShimCacheAge
.Flink
;
399 while (ListEntry
!= &ApphelpShimCacheAge
)
401 PSHIM_CACHE_ENTRY Entry
= CONTAINING_RECORD(ListEntry
, SHIM_CACHE_ENTRY
, List
);
402 USHORT ImageNameLen
= Entry
->Persistent
.ImageName
.MaximumLength
;
403 /* Copy the Persistent structure over */
404 *WriteEntry
= Entry
->Persistent
;
405 BufferNamePos
-= ImageNameLen
;
406 /* Copy the image name over */
407 RtlCopyMemory(BufferNamePos
, Entry
->Persistent
.ImageName
.Buffer
, ImageNameLen
);
408 /* Fix the Persistent structure, so that Buffer is once again an offset */
409 WriteEntry
->ImageName
.Buffer
= (PWCH
)(BufferNamePos
- Buffer
);
412 ListEntry
= ListEntry
->Flink
;
414 ApphelpCacheReleaseLock();
416 Status
= ZwOpenKey(&KeyHandle
, KEY_SET_VALUE
, &AppCompatKeyAttributes
);
417 if (NT_SUCCESS(Status
))
419 Status
= ZwSetValueKey(KeyHandle
,
420 &AppCompatCacheValue
,
429 DPRINT1("SHIMS: ApphelpCacheWrite could not even open Session Manager\\AppCompatCache (0x%x)\n", Status
);
433 return NT_SUCCESS(Status
);
440 ApphelpCacheInitialize(VOID
)
442 DPRINT("SHIMS: ApphelpCacheInitialize\n");
443 /* If we are booting in safemode we do not want to use the apphelp cache */
444 if (InitSafeBootMode
)
446 DPRINT1("SHIMS: Safe mode detected, disabling cache.\n");
447 ApphelpCacheEnabled
= FALSE
;
451 ExInitializeResourceLite(&ApphelpCacheLock
);
452 RtlInitializeGenericTableAvl(&ApphelpShimCache
,
453 ApphelpShimCacheCompareRoutine
,
454 ApphelpShimCacheAllocateRoutine
,
455 ApphelpShimCacheFreeRoutine
,
457 InitializeListHead(&ApphelpShimCacheAge
);
458 ApphelpCacheEnabled
= ApphelpCacheRead();
460 DPRINT("SHIMS: ApphelpCacheInitialize: %d\n", ApphelpCacheEnabled
);
461 return STATUS_SUCCESS
;
466 ApphelpCacheShutdown(VOID
)
468 if (ApphelpCacheEnabled
)
476 _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData
,
477 _Out_ PUNICODE_STRING ImageName
,
478 _Out_ PHANDLE ImageHandle
)
480 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
484 UNICODE_STRING LocalImageName
;
487 ProbeForRead(ServiceData
,
488 sizeof(APPHELP_CACHE_SERVICE_LOOKUP
),
490 LocalImageName
= ServiceData
->ImageName
;
491 *ImageHandle
= ServiceData
->ImageHandle
;
492 if (LocalImageName
.Length
&& LocalImageName
.Buffer
)
494 ProbeForRead(LocalImageName
.Buffer
,
495 LocalImageName
.Length
* sizeof(WCHAR
),
497 ApphelpDuplicateUnicodeString(ImageName
, &LocalImageName
);
498 Status
= STATUS_SUCCESS
;
501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
503 _SEH2_YIELD(return _SEH2_GetExceptionCode());
507 if (!NT_SUCCESS(Status
))
509 DPRINT1("SHIMS: ApphelpValidateData: invalid data passed\n");
515 ApphelpCacheRemoveEntryNolock(
516 _In_ PSHIM_CACHE_ENTRY Entry
)
520 PWSTR Buffer
= Entry
->Persistent
.ImageName
.Buffer
;
521 RemoveEntryList(&Entry
->List
);
522 if (RtlDeleteElementGenericTableAvl(&ApphelpShimCache
, Entry
))
526 return STATUS_SUCCESS
;
528 return STATUS_NOT_FOUND
;
532 ApphelpCacheLookupEntry(
533 _In_ PUNICODE_STRING ImageName
,
534 _In_ HANDLE ImageHandle
)
536 NTSTATUS Status
= STATUS_NOT_FOUND
;
537 SHIM_CACHE_ENTRY Lookup
= EMPTY_SHIM_ENTRY
;
538 PSHIM_CACHE_ENTRY Entry
;
540 if (!ApphelpCacheTryAcquireLock())
545 Lookup
.Persistent
.ImageName
= *ImageName
;
546 Entry
= RtlLookupElementGenericTableAvl(&ApphelpShimCache
, &Lookup
);
549 DPRINT("SHIMS: ApphelpCacheLookupEntry: could not find %wZ\n", ImageName
);
553 DPRINT("SHIMS: ApphelpCacheLookupEntry: found %wZ\n", ImageName
);
554 if (ImageHandle
== INVALID_HANDLE_VALUE
)
556 DPRINT("SHIMS: ApphelpCacheLookupEntry: ok\n");
557 /* just return if we know it, do not query file info */
558 Status
= STATUS_SUCCESS
;
562 Status
= ApphelpCacheQueryInfo(ImageHandle
, &Lookup
);
563 if (NT_SUCCESS(Status
) &&
564 Lookup
.Persistent
.DateTime
.QuadPart
== Entry
->Persistent
.DateTime
.QuadPart
&&
565 Lookup
.Persistent
.FileSize
.QuadPart
== Entry
->Persistent
.FileSize
.QuadPart
)
567 DPRINT("SHIMS: ApphelpCacheLookupEntry: found & validated\n");
568 Status
= STATUS_SUCCESS
;
569 /* move it to the front to keep it alive */
570 RemoveEntryList(&Entry
->List
);
571 InsertHeadList(&ApphelpShimCacheAge
, &Entry
->List
);
575 DPRINT1("SHIMS: ApphelpCacheLookupEntry: file info mismatch (%lx)\n", Status
);
576 Status
= STATUS_NOT_FOUND
;
577 /* Could not read file info, or it did not match, drop it from the cache */
578 ApphelpCacheRemoveEntryNolock(Entry
);
583 ApphelpCacheReleaseLock();
588 ApphelpCacheRemoveEntry(
589 _In_ PUNICODE_STRING ImageName
)
591 PSHIM_CACHE_ENTRY Entry
;
594 ApphelpCacheAcquireLock();
595 Entry
= RtlLookupElementGenericTableAvl(&ApphelpShimCache
, ImageName
);
596 Status
= ApphelpCacheRemoveEntryNolock(Entry
);
597 ApphelpCacheReleaseLock();
601 /* Validate that we are either called from r0, or from a service-like context */
603 ApphelpCacheAccessCheck(VOID
)
605 if (ExGetPreviousMode() != KernelMode
)
607 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, UserMode
))
609 DPRINT1("SHIMS: ApphelpCacheAccessCheck failed\n");
610 return STATUS_ACCESS_DENIED
;
613 return STATUS_SUCCESS
;
617 ApphelpCacheUpdateEntry(
618 _In_ PUNICODE_STRING ImageName
,
619 _In_ HANDLE ImageHandle
)
621 NTSTATUS Status
= STATUS_SUCCESS
;
622 SHIM_CACHE_ENTRY Entry
= EMPTY_SHIM_ENTRY
;
623 PSHIM_CACHE_ENTRY Lookup
;
625 TABLE_SEARCH_RESULT SearchResult
;
627 ApphelpCacheAcquireLock();
629 /* If we got a file handle, query it for info */
630 if (ImageHandle
!= INVALID_HANDLE_VALUE
)
632 Status
= ApphelpCacheQueryInfo(ImageHandle
, &Entry
);
633 if (!NT_SUCCESS(Status
))
639 /* Use ImageName for the lookup, don't actually duplicate it */
640 Entry
.Persistent
.ImageName
= *ImageName
;
641 Lookup
= RtlLookupElementGenericTableFullAvl(&ApphelpShimCache
,
643 &NodeOrParent
, &SearchResult
);
646 DPRINT("SHIMS: ApphelpCacheUpdateEntry: Entry already exists, reusing it\n");
647 /* Unlink the found item, so we can put it back at the front,
648 and copy the earlier obtained file info*/
649 RemoveEntryList(&Lookup
->List
);
650 Lookup
->Persistent
.DateTime
= Entry
.Persistent
.DateTime
;
651 Lookup
->Persistent
.FileSize
= Entry
.Persistent
.FileSize
;
655 DPRINT("SHIMS: ApphelpCacheUpdateEntry: Inserting new Entry\n");
656 /* Insert a new entry, with its own copy of the ImageName */
657 ApphelpDuplicateUnicodeString(&Entry
.Persistent
.ImageName
, ImageName
);
658 Lookup
= RtlInsertElementGenericTableFullAvl(&ApphelpShimCache
,
666 ApphelpFreeUnicodeString(&Entry
.Persistent
.ImageName
);
667 Status
= STATUS_NO_MEMORY
;
672 /* Either we re-used an existing item, or we inserted a new one, keep it alive */
673 InsertHeadList(&ApphelpShimCacheAge
, &Lookup
->List
);
674 if (RtlNumberGenericTableElementsAvl(&ApphelpShimCache
) > MAX_SHIM_ENTRIES
)
676 PSHIM_CACHE_ENTRY Remove
;
677 DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Cache growing too big, dropping oldest item\n");
678 Remove
= CONTAINING_RECORD(ApphelpShimCacheAge
.Blink
, SHIM_CACHE_ENTRY
, List
);
679 Status
= ApphelpCacheRemoveEntryNolock(Remove
);
684 ApphelpCacheReleaseLock();
689 ApphelpCacheFlush(VOID
)
693 DPRINT1("SHIMS: ApphelpCacheFlush\n");
694 ApphelpCacheAcquireLock();
695 while ((p
= RtlEnumerateGenericTableAvl(&ApphelpShimCache
, TRUE
)))
697 ApphelpCacheRemoveEntryNolock((PSHIM_CACHE_ENTRY
)p
);
699 ApphelpCacheReleaseLock();
700 return STATUS_SUCCESS
;
704 ApphelpCacheDump(VOID
)
706 PLIST_ENTRY ListEntry
;
707 PSHIM_CACHE_ENTRY Entry
;
709 DPRINT1("SHIMS: NtApphelpCacheControl( Dumping entries, newest to oldest )\n");
710 ApphelpCacheAcquireLock();
711 ListEntry
= ApphelpShimCacheAge
.Flink
;
712 while (ListEntry
!= &ApphelpShimCacheAge
)
714 Entry
= CONTAINING_RECORD(ListEntry
, SHIM_CACHE_ENTRY
, List
);
715 DPRINT1("Entry: %wZ\n", &Entry
->Persistent
.ImageName
);
716 DPRINT1("DateTime: 0x%I64x\n", Entry
->Persistent
.DateTime
.QuadPart
);
717 DPRINT1("FileSize: 0x%I64x\n", Entry
->Persistent
.FileSize
.QuadPart
);
718 DPRINT1("Flags: 0x%x\n", Entry
->CompatFlags
);
719 ListEntry
= ListEntry
->Flink
;
721 ApphelpCacheReleaseLock();
722 return STATUS_SUCCESS
;
725 /* PUBLIC FUNCTIONS **********************************************************/
729 NtApphelpCacheControl(
730 _In_ APPHELPCACHESERVICECLASS Service
,
731 _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData
)
733 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
734 UNICODE_STRING ImageName
= { 0 };
735 HANDLE Handle
= INVALID_HANDLE_VALUE
;
737 if (!ApphelpCacheEnabled
)
739 DPRINT1("NtApphelpCacheControl: ApphelpCacheEnabled == 0\n");
744 case ApphelpCacheServiceLookup
:
745 DPRINT("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceLookup )\n");
746 Status
= ApphelpValidateData(ServiceData
, &ImageName
, &Handle
);
747 if (NT_SUCCESS(Status
))
748 Status
= ApphelpCacheLookupEntry(&ImageName
, Handle
);
750 case ApphelpCacheServiceRemove
:
751 DPRINT("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceRemove )\n");
752 Status
= ApphelpValidateData(ServiceData
, &ImageName
, &Handle
);
753 if (NT_SUCCESS(Status
))
754 Status
= ApphelpCacheRemoveEntry(&ImageName
);
756 case ApphelpCacheServiceUpdate
:
757 DPRINT("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceUpdate )\n");
758 Status
= ApphelpCacheAccessCheck();
759 if (NT_SUCCESS(Status
))
761 Status
= ApphelpValidateData(ServiceData
, &ImageName
, &Handle
);
762 if (NT_SUCCESS(Status
))
763 Status
= ApphelpCacheUpdateEntry(&ImageName
, Handle
);
766 case ApphelpCacheServiceFlush
:
767 Status
= ApphelpCacheFlush();
769 case ApphelpCacheServiceDump
:
770 Status
= ApphelpCacheDump();
772 case ApphelpDBGReadRegistry
:
773 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGReadRegistry ): flushing cache.\n");
775 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGReadRegistry ): reading cache.\n");
776 Status
= ApphelpCacheRead() ? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
778 case ApphelpDBGWriteRegistry
:
779 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGWriteRegistry ): writing cache.\n");
780 Status
= ApphelpCacheWrite() ? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
783 DPRINT1("SHIMS: NtApphelpCacheControl( Invalid service requested )\n");
786 if (ImageName
.Buffer
)
788 ApphelpFreeUnicodeString(&ImageName
);